Skip to content

Commit

Permalink
semantic analysis now support prefix, infix and arguments of functions
Browse files Browse the repository at this point in the history
  • Loading branch information
gravataLonga committed Jul 9, 2022
1 parent f949d89 commit 3401256
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 8 deletions.
24 changes: 16 additions & 8 deletions semantic/semantic.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,17 @@ func (s *Semantic) exitScope() {
}

// declare will keep track of declare variables
func (s *Semantic) declare(node *ast.VarStatement) {
func (s *Semantic) declare(name string) {
if s.scopeStack.IsEmpty() {
return
}

peek, _ := s.scopeStack.Peek()
(*peek)[node.Name.Value] = false
(*peek)[name] = false
}

// resolve after a variable been resolve we mark it as resolved.
func (s *Semantic) resolve(node *ast.VarStatement) {
name := node.Name.Value
func (s *Semantic) resolve(name string) {
peek, ok := s.scopeStack.Peek()
if !ok {
return
Expand Down Expand Up @@ -104,21 +103,30 @@ func (s *Semantic) analysis(node ast.Node) ast.Node {
case *ast.Identifier:
s.expectIdentifierDeclare(node)
case *ast.VarStatement:
s.declare(node)
s.declare(node.Name.Value)
if _, ok := node.Value.(ast.Expression); ok {
s.analysis(node.Value)
}
s.resolve(node)
s.resolve(node.Name.Value)
case *ast.ExpressionStatement:
s.analysis(node.Expression)
case *ast.PrefixExpression:
s.analysis(node.Right)
case *ast.InfixExpression:
s.analysis(node.Left)
s.analysis(node.Right)
case *ast.FunctionLiteral:
s.newScope()
for _, arg := range node.Parameters {
s.declare(arg.Value)
s.resolve(arg.Value)
}
s.analysis(node.Body)
s.exitScope()
case *ast.BlockStatement:
s.newScope()
for _, b := range node.Statements {
s.analysis(b)
}
s.exitScope()
}
return node
}
40 changes: 40 additions & 0 deletions semantic/semantic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,30 @@ func TestScopeVariable(t *testing.T) {
{
`function () { var a = true; var b = a; }`,
},
{
`var a = 1`,
},
{
`var a = true`,
},
{
`var a = []`,
},
{
`var a = {}`,
},
{
`function (x) { return x; }`,
},
{
`function () { function (y) { var a = y + 1; } }`,
},
{
`function () { var a = -1; }`,
},
{
`function () { var a = !true; }`,
},
}

for i, tt := range tests {
Expand All @@ -43,6 +67,10 @@ func TestScopeVariablesWrong(t *testing.T) {
`function () { var a = a; }`,
"Can't read local variable \"a\" in its own initializer IDENT at [Line: 1, Offset: 24]",
},
{
`function () { var a = a + 1 }`,
"Can't read local variable \"a\" in its own initializer IDENT at [Line: 1, Offset: 24]",
},
{
`function () { var a = [1, b]; }`,
"Variable \"b\" not declare yet IDENT at [Line: 1, Offset: 28]",
Expand Down Expand Up @@ -75,6 +103,18 @@ func TestScopeVariablesWrong(t *testing.T) {
`function () { var a = "local"; function () { var a = a; } }`,
"Can't read local variable \"a\" in its own initializer IDENT at [Line: 1, Offset: 55]",
},
{
`function () { var a = "local"; function () { function () { var a = a; } } }`,
"Can't read local variable \"a\" in its own initializer IDENT at [Line: 1, Offset: 69]",
},
{
`function () { function (y) { var a = x + 1; } }`,
`Variable "x" not declare yet IDENT at [Line: 1, Offset: 39]`,
},
{
`function () { var a = !x; }`,
`Variable "x" not declare yet IDENT at [Line: 1, Offset: 25]`,
},
}

for i, tt := range tests {
Expand Down

0 comments on commit 3401256

Please sign in to comment.