Skip to content

Commit

Permalink
Added Register (for int64) type. (#240)
Browse files Browse the repository at this point in the history
* Added Register (for int64) type. Rename object.Value() ObjValue() so an object can be both ast.Node and ast.Object

* linter

* Verify in log verbose that the substitution of registers work, improve slightly perf

* make register a pointer to save a ton of alloc and return them unchanged

* setup registers for (integer) function arguments too - boxed_text.gr is erroring out so this is a checkpoint

* wip fixing the scripts... but ... maybe it's not good to have to make all these changes that registers break

* fix array with registers

* split CopyRegister value from Value() so object arrays passed to type() retain the reference types

* Fix #224

* make str() a built in with correct [] wrapping needed. adding new test file forgotten earlier.

* more details on NoErr regexp mismatch, reduced the failure

* further reduce

* Change modify to allow abort/ok/not ok results; allows to drop ok field from register and stop early when needed

* linters

* update scripts for int to float issues

* Faster examples for regular tests

* Adding another prime sieve example
  • Loading branch information
ldemailly authored Sep 20, 2024
1 parent 1cb0491 commit ab2ebd3
Show file tree
Hide file tree
Showing 22 changed files with 654 additions and 255 deletions.
134 changes: 109 additions & 25 deletions ast/modify.go
Original file line number Diff line number Diff line change
@@ -1,62 +1,124 @@
package ast

import "fmt"
import (
"fmt"

"fortio.org/log"
)

func ModifyNoOk(node Node, f func(Node) Node) Node {
newNode, _ := Modify(node, func(n Node) (Node, bool) {
return f(n), true
})
return newNode
}

// Note, this is somewhat similar to eval.go's eval... both are "apply"ing.
func Modify(node Node, f func(Node) Node) Node { //nolint:funlen,gocyclo,gocognit // yeah lots of types.
// TODO: add err checks for _s.
func Modify(node Node, f func(Node) (Node, bool)) (Node, bool) { //nolint:funlen,gocyclo,gocognit,maintidx // yeah lots of types.
// It's quite ugly all these continuation/ok checks.
var cont bool
switch node := node.(type) {
case *Statements:
newNode := &Statements{Base: node.Base, Statements: make([]Node, len(node.Statements))}
for i, statement := range node.Statements {
newNode.Statements[i] = Modify(statement, f)
newNode.Statements[i], cont = Modify(statement, f)
if !cont {
return nil, false
}
}
return f(newNode)
case *InfixExpression:
newNode := &InfixExpression{Base: node.Base}
newNode.Left = Modify(node.Left, f)
newNode.Right = Modify(node.Right, f)
newNode.Left, cont = Modify(node.Left, f)
if !cont {
return nil, false
}
newNode.Right, cont = Modify(node.Right, f)
if !cont {
return nil, false
}
return f(newNode)
case *PrefixExpression:
newNode := &PrefixExpression{Base: node.Base}
newNode.Right = Modify(node.Right, f)
newNode.Right, cont = Modify(node.Right, f)
if !cont {
return nil, false
}
return f(newNode)
case *IndexExpression:
newNode := &IndexExpression{Base: node.Base}
newNode.Left = Modify(node.Left, f)
newNode.Index = Modify(node.Index, f)
newNode.Left, cont = Modify(node.Left, f)
if !cont {
return nil, false
}
newNode.Index, cont = Modify(node.Index, f)
if !cont {
return nil, false
}
return f(newNode)
case *IfExpression:
newNode := &IfExpression{Base: node.Base}
newNode.Condition = Modify(node.Condition, f)
newNode.Consequence = Modify(node.Consequence, f).(*Statements)
newNode.Condition, cont = Modify(node.Condition, f)
if !cont {
return nil, false
}
nc, ok := Modify(node.Consequence, f)
if !ok {
return nil, false
}
newNode.Consequence = nc.(*Statements)
if node.Alternative != nil {
newNode.Alternative = Modify(node.Alternative, f).(*Statements)
nc, ok = Modify(node.Alternative, f)
if !ok {
return nil, false
}
newNode.Alternative = nc.(*Statements)
}
return f(newNode)
case *ForExpression:
newNode := &ForExpression{Base: node.Base}
newNode.Condition = Modify(node.Condition, f)
newNode.Body = Modify(node.Body, f).(*Statements)
newNode.Condition, cont = Modify(node.Condition, f)
if !cont {
return nil, false
}
nb, ok := Modify(node.Body, f)
if !ok {
return nil, false
}
newNode.Body = nb.(*Statements)
return f(newNode)
case *ReturnStatement:
newNode := &ReturnStatement{Base: node.Base}
if node.ReturnValue != nil {
newNode.ReturnValue = Modify(node.ReturnValue, f)
newNode.ReturnValue, cont = Modify(node.ReturnValue, f)
if !cont {
return nil, false
}
}
return f(newNode)
case *FunctionLiteral:
newNode := *node
newNode.Parameters = make([]Node, len(node.Parameters))
for i := range node.Parameters {
newNode.Parameters[i] = Modify(node.Parameters[i], f).(*Identifier)
id, ok := Modify(node.Parameters[i], f)
if !ok {
return nil, false
}
newNode.Parameters[i] = id.(*Identifier)
}
newNode.Body = Modify(node.Body, f).(*Statements)
nb, ok := Modify(node.Body, f)
if !ok {
return nil, false
}
newNode.Body = nb.(*Statements)
return f(&newNode)
case *ArrayLiteral:
newNode := &ArrayLiteral{Base: node.Base, Elements: make([]Node, len(node.Elements))}
for i := range node.Elements {
newNode.Elements[i] = Modify(node.Elements[i], f)
newNode.Elements[i], cont = Modify(node.Elements[i], f)
if !cont {
return nil, false
}
}
return f(newNode)
case *MapLiteral:
Expand All @@ -66,9 +128,15 @@ func Modify(node Node, f func(Node) Node) Node { //nolint:funlen,gocyclo,gocogni
if !ok {
panic(fmt.Sprintf("key %v not in pairs for map %v", key, node))
}
newKey := Modify(key, f)
newKey, ok := Modify(key, f)
if !ok {
return nil, false
}
newNode.Order = append(newNode.Order, newKey)
newNode.Pairs[newKey] = Modify(val, f)
newNode.Pairs[newKey], cont = Modify(val, f)
if !cont {
return nil, false
}
}
return f(newNode)
case *Identifier:
Expand Down Expand Up @@ -98,26 +166,42 @@ func Modify(node Node, f func(Node) Node) Node { //nolint:funlen,gocyclo,gocogni
case *Builtin:
newNode := &Builtin{Base: node.Base, Parameters: make([]Node, len(node.Parameters))}
for i := range node.Parameters {
newNode.Parameters[i] = Modify(node.Parameters[i], f)
newNode.Parameters[i], cont = Modify(node.Parameters[i], f)
if !cont {
return nil, false
}
}
return f(newNode)
case *CallExpression:
newNode := *node
newNode.Arguments = make([]Node, len(node.Arguments))
for i := range node.Arguments {
newNode.Arguments[i] = Modify(node.Arguments[i], f)
newNode.Arguments[i], cont = Modify(node.Arguments[i], f)
if !cont {
return nil, false
}
}
return f(&newNode)
case *MacroLiteral:
// modifying macro itself may be pointless but for completeness.
newNode := *node
newNode.Parameters = make([]Node, len(node.Parameters))
for i := range node.Parameters {
newNode.Parameters[i] = Modify(node.Parameters[i], f).(*Identifier)
id, ok := Modify(node.Parameters[i], f)
if !ok {
return nil, false
}
newNode.Parameters[i] = id.(*Identifier)
}
nb, ok := Modify(node.Body, f)
if !ok {
return nil, false
}
newNode.Body = Modify(node.Body, f).(*Statements)
newNode.Body = nb.(*Statements)
return f(&newNode)
default:
panic(fmt.Sprintf("Modify not implemented for node type %T", node))
log.Debugf("Modify not implemented for node type %T", node)
return f(node)
// panic(fmt.Sprintf("Modify not implemented for node type %T", node))
}
}
6 changes: 3 additions & 3 deletions ast/modify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ var (
}
)

func TestModify(t *testing.T) {
func TestModifyNoOk(t *testing.T) {
tests := []struct {
input Node
expected Node
Expand Down Expand Up @@ -107,7 +107,7 @@ func TestModify(t *testing.T) {
},
}
for _, tt := range tests {
modified := Modify(tt.input, turnOneIntoTwo)
modified := ModifyNoOk(tt.input, turnOneIntoTwo)
if !reflect.DeepEqual(modified, tt.expected) {
t.Errorf("not equal.\n%#v\n-vs-\n%#v", modified, tt.expected)
}
Expand All @@ -117,7 +117,7 @@ func TestModify(t *testing.T) {
func TestModifyMap(t *testing.T) {
// need to test map separately because deepequal can't compare a map
// with keys of the same underlying value (2:2, 2:2)
modified := Modify(
modified := ModifyNoOk(
&MapLiteral{
Pairs: map[Node]Node{
aone: one(),
Expand Down
Loading

0 comments on commit ab2ebd3

Please sign in to comment.