summaryrefslogtreecommitdiff
path: root/vm0
diff options
context:
space:
mode:
authorMarc Vertes <marc.vertes@tendermint.com>2023-07-24 14:19:42 +0200
committerGitHub <noreply@github.com>2023-07-24 14:19:42 +0200
commitbf32256ff3014543ef5dda69c4ee1e94d01361fe (patch)
tree7ed1080462ed45864704a276eabaefa1fc299d8d /vm0
parentaa4cc2b45ebadf4cea16d1e27149e13669f3a5fc (diff)
parser: define all node kinds to make the parser multi-language (#3)
* parser: define all node kinds to make the parser multi-language Defining all AST node kinds in the parser is necessary to make the parser really multi-language. If a language requires a node kind not already present in parser/kind.go, it will be necessary to add it first here. Note that as long as a node kind subtree is structurally identical between languages, even if there are lexical and/or syntaxic differences, it can (and must) be shared amongst multiple language definitions. For example, an "if" statememt in shell script or in C code should give the same `IfStmt` at AST level. In order to let the parser deal with the various language syntaxes, and produce the right node kind and subtree, parser flags will be set in language definitions (see `Flags` field in `NodeSpec` struct). * lang/golang: use parser node kinds * vm0: remode dependency on language definition.
Diffstat (limited to 'vm0')
-rw-r--r--vm0/vm.go42
1 files changed, 24 insertions, 18 deletions
diff --git a/vm0/vm.go b/vm0/vm.go
index 4c726ed..3e589ed 100644
--- a/vm0/vm.go
+++ b/vm0/vm.go
@@ -2,10 +2,8 @@ package vm0
import (
"fmt"
- "strconv"
"strings"
- "github.com/gnolang/parscan/lang/golang"
"github.com/gnolang/parscan/parser"
)
@@ -37,14 +35,14 @@ func (i *Interp) Eval(src string) (r []any, err error) {
}
// Run implements a stack based virtual machine which directly walks the AST.
-func (i *Interp) Run(node *parser.Node, scope string) ([]any, error) {
+func (i *Interp) Run(node *parser.Node, scope string) (res []any, err error) {
stop := false
node.Walk2(nil, 0, func(n, a *parser.Node, k int) (ok bool) {
// Node pre-order processing.
switch n.Kind {
- case golang.StmtBloc:
- if a != nil && a.Kind == golang.IfStmt {
+ case parser.StmtBloc:
+ if a != nil && a.Kind == parser.IfStmt {
// Control-flow in 'if' sub-tree
if k == 1 {
// 'if' first body branch, evaluated when condition is true.
@@ -56,7 +54,7 @@ func (i *Interp) Run(node *parser.Node, scope string) ([]any, error) {
// 'else' body branch, evaluated when condition is false.
return !i.pop().(bool)
}
- case golang.FuncDecl:
+ case parser.FuncDecl:
i.declareFunc(n, scope)
return false
}
@@ -68,33 +66,41 @@ func (i *Interp) Run(node *parser.Node, scope string) ([]any, error) {
}
l := len(i.stack)
switch n.Kind {
- case golang.NumberLit:
- num, _ := strconv.Atoi(n.Content()) // TODO(marc): compute num value at scanning.
- i.push(num)
- case golang.StringLit:
+ case parser.NumberLit:
+ switch v := n.Value().(type) {
+ case int64:
+ i.push(int(v))
+ case error:
+ err = v
+ return false
+ default:
+ err = fmt.Errorf("type not supported: %T\n", v)
+ return false
+ }
+ case parser.StringLit:
i.push(n.Block())
- case golang.InfOp:
+ case parser.InfOp:
i.stack[l-2] = i.stack[l-2].(int) < i.stack[l-1].(int)
i.stack = i.stack[:l-1]
- case golang.AddOp:
+ case parser.AddOp:
i.stack[l-2] = i.stack[l-2].(int) + i.stack[l-1].(int)
i.stack = i.stack[:l-1]
- case golang.SubOp:
+ case parser.SubOp:
i.stack[l-2] = i.stack[l-2].(int) - i.stack[l-1].(int)
i.stack = i.stack[:l-1]
- case golang.MulOp:
+ case parser.MulOp:
i.stack[l-2] = i.stack[l-2].(int) * i.stack[l-1].(int)
i.stack = i.stack[:l-1]
- case golang.AssignOp, golang.DefOp:
+ case parser.AssignOp, parser.DefOp:
i.stack[i.stack[l-2].(int)] = i.stack[l-1]
i.stack = i.stack[:l-2]
- case golang.ReturnStmt:
+ case parser.ReturnStmt:
stop = true
return false
- case golang.CallExpr:
+ case parser.CallExpr:
i.push(len(n.Child[1].Child)) // number of arguments to call
i.callFunc(n)
- case golang.Ident:
+ case parser.Ident:
name := n.Content()
v, sc, ok := i.getSym(name, scope)
fp := i.fp