Skip to content

Commit

Permalink
starting adding semantic analyzer between parser and evaluator
Browse files Browse the repository at this point in the history
  • Loading branch information
gravataLonga committed Jul 8, 2022
1 parent 28585fa commit 95ad14d
Show file tree
Hide file tree
Showing 39 changed files with 463 additions and 65 deletions.
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ For more detail about language, you can check [here](https://ninja.jonathan.pt)

# Demo

Resolving katas you can check this repository
https://adventofcode.com/2015
Resolved [katas](https://github.com/gravataLonga/ninja-lang-katas) from this [website](https://adventofcode.com/2015)

# Syntax

Expand Down Expand Up @@ -484,6 +483,24 @@ var true false function delete enum
return if else for import break case
```

## Lexical Scooping

[Inspiration](https://craftinginterpreters.com/resolving-and-binding.html)

> To “resolve” a variable usage, we only need to calculate how many “hops” away the declared variable will be in the
> environment chain. The interesting question is when to do this calculation—or, put differently, where in our
> interpreter’s implementation do we stuff the code for it?
## A variable resolution pass

> After the parser produces the syntax tree, but before the interpreter starts executing it, we’ll do a single walk over
> the tree to resolve all of the variables it contains. Additional passes between parsing and execution are common.
> If Lox had static types, we could slide a type checker in there. Optimizations are often implemented in separate
> passes like this too. Basically, any work that doesn't rely on state that’s only available at runtime can be done
> in this way.
When binding a variable we need to know how depth we are in rabbit hole.

## Examples

1. Check tests
Expand Down
2 changes: 1 addition & 1 deletion ast/array_literal.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type ArrayLiteral struct {
}

func (al *ArrayLiteral) expressionNode() {}
func (al *ArrayLiteral) TokenLiteral() string { return string(al.Token.Literal) }
func (al *ArrayLiteral) TokenLiteral() string { return al.Token.Literal }
func (al *ArrayLiteral) String() string {
var out bytes.Buffer
elements := make([]string, len(al.Elements))
Expand Down
2 changes: 1 addition & 1 deletion ast/block_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type BlockStatement struct {
}

func (bs *BlockStatement) statementNode() {}
func (bs *BlockStatement) TokenLiteral() string { return string(bs.Token.Literal) }
func (bs *BlockStatement) TokenLiteral() string { return bs.Token.Literal }
func (bs *BlockStatement) String() string {
var out bytes.Buffer
for _, s := range bs.Statements {
Expand Down
4 changes: 2 additions & 2 deletions ast/boolean.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ type Boolean struct {
}

func (il *Boolean) expressionNode() {}
func (il *Boolean) TokenLiteral() string { return string(il.Token.Literal) }
func (il *Boolean) String() string { return string(il.Token.Literal) }
func (il *Boolean) TokenLiteral() string { return il.Token.Literal }
func (il *Boolean) String() string { return il.Token.Literal }
2 changes: 1 addition & 1 deletion ast/break.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type BreakStatement struct {
}

func (rs *BreakStatement) statementNode() {}
func (rs *BreakStatement) TokenLiteral() string { return string(rs.Token.Literal) }
func (rs *BreakStatement) TokenLiteral() string { return rs.Token.Literal }
func (rs *BreakStatement) String() string {
return rs.TokenLiteral()
}
2 changes: 1 addition & 1 deletion ast/call_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type CallExpression struct {
}

func (ce *CallExpression) expressionNode() {}
func (ce *CallExpression) TokenLiteral() string { return string(ce.Token.Literal) }
func (ce *CallExpression) TokenLiteral() string { return ce.Token.Literal }
func (ce *CallExpression) String() string {
var out bytes.Buffer
args := make([]string, len(ce.Arguments))
Expand Down
2 changes: 1 addition & 1 deletion ast/delete_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type DeleteStatement struct {
}

func (de *DeleteStatement) statementNode() {}
func (de *DeleteStatement) TokenLiteral() string { return string(de.Token.Literal) }
func (de *DeleteStatement) TokenLiteral() string { return de.Token.Literal }
func (de *DeleteStatement) String() string {
var out bytes.Buffer

Expand Down
4 changes: 2 additions & 2 deletions ast/expression_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package ast
import "ninja/token"

type ExpressionStatement struct {
Token token.Token // the first token of the expression
Token token.Token
Expression Expression
}

func (es *ExpressionStatement) statementNode() {}
func (es *ExpressionStatement) TokenLiteral() string { return string(es.Token.Literal) }
func (es *ExpressionStatement) TokenLiteral() string { return es.Token.Literal }
func (es *ExpressionStatement) String() string {
if es.Expression != nil {
return es.Expression.String()
Expand Down
7 changes: 1 addition & 6 deletions ast/float_literal.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ type FloatLiteral struct {
}

func (il *FloatLiteral) expressionNode() {}
func (il *FloatLiteral) TokenLiteral() string { return string(il.Token.Literal) }
func (il *FloatLiteral) TokenLiteral() string { return il.Token.Literal }
func (il *FloatLiteral) String() string {
return string(il.Token.Literal)
}

// ToBeDeleted return always smallest decimal place
func ToBeDeleted(f float64, precision uint) float64 {
return f
}
2 changes: 1 addition & 1 deletion ast/for_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type ForStatement struct {
}

func (fs *ForStatement) expressionNode() {}
func (fs *ForStatement) TokenLiteral() string { return string(fs.Token.Literal) }
func (fs *ForStatement) TokenLiteral() string { return fs.Token.Literal }
func (fs *ForStatement) String() string {
var out bytes.Buffer

Expand Down
2 changes: 1 addition & 1 deletion ast/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type Function struct {
}

func (fl *Function) expressionNode() {}
func (fl *Function) TokenLiteral() string { return string(fl.Token.Literal) }
func (fl *Function) TokenLiteral() string { return fl.Token.Literal }
func (fl *Function) String() string {
var out bytes.Buffer
params := make([]string, len(fl.Parameters))
Expand Down
2 changes: 1 addition & 1 deletion ast/function_literal.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type FunctionLiteral struct {
}

func (fl *FunctionLiteral) expressionNode() {}
func (fl *FunctionLiteral) TokenLiteral() string { return string(fl.Token.Literal) }
func (fl *FunctionLiteral) TokenLiteral() string { return fl.Token.Literal }
func (fl *FunctionLiteral) String() string {
var out bytes.Buffer
params := make([]string, len(fl.Parameters))
Expand Down
2 changes: 1 addition & 1 deletion ast/function_literal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func TestFunctionLiteral_String(t *testing.T) {
}

blockStatement := &BlockStatement{Token: token.Token{Type: token.LBRACE, Literal: "{"}, Statements: stmts}
argumentsIdentifier := []*Identifier{}
var argumentsIdentifier []*Identifier
for _, arg := range tt.parameters {
integerLiteral := &Identifier{Token: token.Token{Type: token.INT, Literal: strconv.FormatInt(arg, 10)}, Value: strconv.FormatInt(arg, 10)}
argumentsIdentifier = append(argumentsIdentifier, integerLiteral)
Expand Down
2 changes: 1 addition & 1 deletion ast/hash_literal.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type HashLiteral struct {
}

func (hl *HashLiteral) expressionNode() {}
func (hl *HashLiteral) TokenLiteral() string { return string(hl.Token.Literal) }
func (hl *HashLiteral) TokenLiteral() string { return hl.Token.Literal }
func (hl *HashLiteral) String() string {
var out bytes.Buffer
pairs := make([]string, len(hl.Pairs))
Expand Down
2 changes: 1 addition & 1 deletion ast/identifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type Identifier struct {
}

func (i *Identifier) expressionNode() {}
func (i *Identifier) TokenLiteral() string { return string(i.Token.Literal) }
func (i *Identifier) TokenLiteral() string { return i.Token.Literal }
func (i *Identifier) String() string {
return i.Value
}
2 changes: 1 addition & 1 deletion ast/if_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type IfExpression struct {
}

func (ie *IfExpression) expressionNode() {}
func (ie *IfExpression) TokenLiteral() string { return string(ie.Token.Literal) }
func (ie *IfExpression) TokenLiteral() string { return ie.Token.Literal }
func (ie *IfExpression) String() string {
var out bytes.Buffer
out.WriteString("if")
Expand Down
2 changes: 1 addition & 1 deletion ast/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type Import struct {
}

func (i *Import) expressionNode() {}
func (i *Import) TokenLiteral() string { return string(i.Token.Literal) }
func (i *Import) TokenLiteral() string { return i.Token.Literal }
func (i *Import) String() string {
var out bytes.Buffer

Expand Down
2 changes: 1 addition & 1 deletion ast/index_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type IndexExpression struct {
}

func (ie *IndexExpression) expressionNode() {}
func (ie *IndexExpression) TokenLiteral() string { return string(ie.Token.Literal) }
func (ie *IndexExpression) TokenLiteral() string { return ie.Token.Literal }
func (ie *IndexExpression) String() string {
var out bytes.Buffer
out.WriteString("(")
Expand Down
2 changes: 1 addition & 1 deletion ast/infix_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type InfixExpression struct {
}

func (oe *InfixExpression) expressionNode() {}
func (oe *InfixExpression) TokenLiteral() string { return string(oe.Token.Literal) }
func (oe *InfixExpression) TokenLiteral() string { return oe.Token.Literal }

func (oe *InfixExpression) String() string {
var out bytes.Buffer
Expand Down
2 changes: 1 addition & 1 deletion ast/integer_literal.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type IntegerLiteral struct {
}

func (il *IntegerLiteral) expressionNode() {}
func (il *IntegerLiteral) TokenLiteral() string { return string(il.Token.Literal) }
func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal }
func (il *IntegerLiteral) String() string {
return il.TokenLiteral()
}
2 changes: 1 addition & 1 deletion ast/object_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type ObjectCall struct {
}

func (oc *ObjectCall) expressionNode() {}
func (oc *ObjectCall) TokenLiteral() string { return string(oc.Token.Literal) }
func (oc *ObjectCall) TokenLiteral() string { return oc.Token.Literal }
func (oc *ObjectCall) String() string {
var out bytes.Buffer
out.WriteString("(")
Expand Down
2 changes: 1 addition & 1 deletion ast/posfix_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type PostfixExpression struct {
}

func (pe *PostfixExpression) expressionNode() {}
func (pe *PostfixExpression) TokenLiteral() string { return string(pe.Token.Literal) }
func (pe *PostfixExpression) TokenLiteral() string { return pe.Token.Literal }

func (pe *PostfixExpression) String() string {
var out bytes.Buffer
Expand Down
2 changes: 1 addition & 1 deletion ast/prefix_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type PrefixExpression struct {
}

func (pe *PrefixExpression) expressionNode() {}
func (pe *PrefixExpression) TokenLiteral() string { return string(pe.Token.Literal) }
func (pe *PrefixExpression) TokenLiteral() string { return pe.Token.Literal }

func (pe *PrefixExpression) String() string {
var out bytes.Buffer
Expand Down
2 changes: 1 addition & 1 deletion ast/return_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type ReturnStatement struct {
}

func (rs *ReturnStatement) statementNode() {}
func (rs *ReturnStatement) TokenLiteral() string { return string(rs.Token.Literal) }
func (rs *ReturnStatement) TokenLiteral() string { return rs.Token.Literal }
func (rs *ReturnStatement) String() string {
var out bytes.Buffer
out.WriteString(rs.TokenLiteral() + " ")
Expand Down
2 changes: 1 addition & 1 deletion ast/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type StringLiteral struct {
}

func (il *StringLiteral) expressionNode() {}
func (il *StringLiteral) TokenLiteral() string { return string(il.Token.Literal) }
func (il *StringLiteral) TokenLiteral() string { return il.Token.Literal }
func (il *StringLiteral) String() string {
return il.TokenLiteral()
}
4 changes: 2 additions & 2 deletions ast/var_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type VarStatement struct {
}

func (ls *VarStatement) statementNode() {}
func (ls *VarStatement) TokenLiteral() string { return string(ls.Token.Literal) }
func (ls *VarStatement) TokenLiteral() string { return ls.Token.Literal }
func (ls *VarStatement) String() string {
var out bytes.Buffer
out.WriteString(ls.TokenLiteral() + " ")
Expand All @@ -35,7 +35,7 @@ type AssignStatement struct {

func (ls *AssignStatement) expressionNode() {}
func (ls *AssignStatement) statementNode() {}
func (ls *AssignStatement) TokenLiteral() string { return string(ls.Token.Literal) }
func (ls *AssignStatement) TokenLiteral() string { return ls.Token.Literal }
func (ls *AssignStatement) String() string {
var out bytes.Buffer
out.WriteString(ls.Name.String())
Expand Down
2 changes: 1 addition & 1 deletion evaluator/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
func Eval(node ast.Node, env *object.Environment) object.Object {
switch node := node.(type) {

// Ast Program Eval
case *ast.Program:
return evalProgram(node.Statements, env)

Expand Down Expand Up @@ -153,6 +152,7 @@ func Eval(node ast.Node, env *object.Environment) object.Object {
case *ast.ScopeOperatorExpression:
return evalScopeOperatorExpression(node, env)
}

return nil
}

Expand Down
8 changes: 4 additions & 4 deletions evaluator/function_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ func TestCallFunction(t *testing.T) {
"function add(a, b) { return function test(x, y) { return a + b + x + y }; } add(10, 10)(10, 10);",
40,
},
//{
// "var a = 0; function add() { return function increment() { a++; return a; }}; var b = add()(); add()();",
// 2,
// },
/*{
"var a = 0; function add() { return function increment() { a++; return a; }}; var b = add()(); add()();",
2,
},*/
}

for i, tt := range tests {
Expand Down
13 changes: 13 additions & 0 deletions object/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,16 @@ func (e *Environment) Set(name string, val Object) Object {
e.store[name] = val
return val
}

/*
func (e *Environment) Set(name string, val Object) Object {
_, ok := e.store[name]
if !ok && e.outer != nil {
e.outer.Set(name, val)
} else {
e.store[name] = val
}
return val
}
*/
5 changes: 5 additions & 0 deletions object/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Cloneable interface {

// Comparable is the interface for comparing two Object and their underlying
// values. It is the responsibility of the caller (left) to check for types.
// E.g.: 1 > 1, it will return -1. left isn't greater than 1.
type Comparable interface {
Compare(right Object) int8
}
Expand Down Expand Up @@ -59,6 +60,10 @@ func IsError(o Object) bool {
}

func IsTruthy(o Object) bool {
if o == nil {
return false
}

switch o.Type() {
case NULL_OBJ:
return false
Expand Down
Loading

0 comments on commit 95ad14d

Please sign in to comment.