Skip to content

Commit

Permalink
Merge pull request #17 from JunNishimura/feature/read_symbol_from_env
Browse files Browse the repository at this point in the history
read symbol from environment
  • Loading branch information
JunNishimura authored Sep 28, 2024
2 parents 5c045b0 + 6bd7d6f commit 1fea968
Show file tree
Hide file tree
Showing 5 changed files with 548 additions and 36 deletions.
9 changes: 7 additions & 2 deletions evaluator/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func Eval(exp ast.Expression, env *object.Environment) object.Object {
}
return evalPrefixAtom(expt.Operator, right)
case *ast.Symbol:
return evalSymbol(expt)
return evalSymbol(expt, env)
case *ast.CommandObject:
return evalCommandObject(expt, env)
case *ast.IfExpression:
Expand Down Expand Up @@ -102,12 +102,17 @@ func evalExclamationPrefix(right object.Object) object.Object {
}
}

func evalSymbol(symbol *ast.Symbol) object.Object {
func evalSymbol(symbol *ast.Symbol, env *object.Environment) object.Object {
builtintFunc, ok := builtins[symbol.Value]
if ok {
return builtintFunc
}

obj, ok := env.Get(symbol.Value)
if ok {
return obj
}

return newError("symbol not found: %s", symbol.Value)
}

Expand Down
58 changes: 58 additions & 0 deletions evaluator/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,3 +399,61 @@ func TestSetExpression(t *testing.T) {
})
}
}

func TestMultipleExpressions(t *testing.T) {
tests := []struct {
name string
input string
expected int64
}{
{
name: "multiple atoms",
input: `
[
1,
2
]`,
expected: 2,
},
{
name: "multiple commands",
input: `
[
{
"command": {
"symbol": "+",
"args": [1, 2]
}
},
{
"command": {
"symbol": "-",
"args": [1, 2]
}
}
]`,
expected: -1,
},
{
name: "multiple commands with set expression",
input: `
[
{
"set": {
"var": "$x",
"val": 10
}
},
"$x"
]`,
expected: 10,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
evaluated := testEval(t, tt.input)
testIntegerObject(t, evaluated, tt.expected)
})
}
}
191 changes: 191 additions & 0 deletions lexer/lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,3 +533,194 @@ func TestSingleProgram(t *testing.T) {
})
}
}

func TestMultiplePrograms(t *testing.T) {
tests := []struct {
name string
input string
expected []token.Token
}{
{
name: "multiple atoms",
input: `
[
1,
2
]
`,
expected: []token.Token{
{Type: token.LBRACKET, Literal: "["},
{Type: token.INT, Literal: "1"},
{Type: token.COMMA, Literal: ","},
{Type: token.INT, Literal: "2"},
{Type: token.RBRACKET, Literal: "]"},
{Type: token.EOF, Literal: ""},
},
},
{
name: "multiple commands",
input: `
[
{
"command": {
"symbol": "+",
"args": [1, 2]
}
},
{
"command": {
"symbol": "-",
"args": [3, 4]
}
}
]
`,
expected: []token.Token{
{Type: token.LBRACKET, Literal: "["},
{Type: token.LBRACE, Literal: "{"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COMMAND, Literal: "command"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COLON, Literal: ":"},
{Type: token.LBRACE, Literal: "{"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.SYMBOLKEY, Literal: "symbol"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COLON, Literal: ":"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.SYMBOL, Literal: "+"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COMMA, Literal: ","},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.ARGS, Literal: "args"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COLON, Literal: ":"},
{Type: token.LBRACKET, Literal: "["},
{Type: token.INT, Literal: "1"},
{Type: token.COMMA, Literal: ","},
{Type: token.INT, Literal: "2"},
{Type: token.RBRACKET, Literal: "]"},
{Type: token.RBRACE, Literal: "}"},
{Type: token.RBRACE, Literal: "}"},
{Type: token.COMMA, Literal: ","},
{Type: token.LBRACE, Literal: "{"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COMMAND, Literal: "command"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COLON, Literal: ":"},
{Type: token.LBRACE, Literal: "{"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.SYMBOLKEY, Literal: "symbol"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COLON, Literal: ":"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.SYMBOL, Literal: "-"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COMMA, Literal: ","},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.ARGS, Literal: "args"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COLON, Literal: ":"},
{Type: token.LBRACKET, Literal: "["},
{Type: token.INT, Literal: "3"},
{Type: token.COMMA, Literal: ","},
{Type: token.INT, Literal: "4"},
{Type: token.RBRACKET, Literal: "]"},
{Type: token.RBRACE, Literal: "}"},
{Type: token.RBRACE, Literal: "}"},
{Type: token.RBRACKET, Literal: "]"},
{Type: token.EOF, Literal: ""},
},
},
{
name: "read symbol from environment",
input: `
[
{
"set": {
"var": "$x",
"val": {
"command": {
"symbol": "+",
"args": [1, 2]
}
}
}
},
"$x"
]
`,
expected: []token.Token{
{Type: token.LBRACKET, Literal: "["},
{Type: token.LBRACE, Literal: "{"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.SET, Literal: "set"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COLON, Literal: ":"},
{Type: token.LBRACE, Literal: "{"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.VAR, Literal: "var"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COLON, Literal: ":"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.DOLLAR, Literal: "$"},
{Type: token.SYMBOL, Literal: "x"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COMMA, Literal: ","},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.VAL, Literal: "val"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COLON, Literal: ":"},
{Type: token.LBRACE, Literal: "{"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COMMAND, Literal: "command"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COLON, Literal: ":"},
{Type: token.LBRACE, Literal: "{"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.SYMBOLKEY, Literal: "symbol"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COLON, Literal: ":"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.SYMBOL, Literal: "+"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COMMA, Literal: ","},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.ARGS, Literal: "args"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.COLON, Literal: ":"},
{Type: token.LBRACKET, Literal: "["},
{Type: token.INT, Literal: "1"},
{Type: token.COMMA, Literal: ","},
{Type: token.INT, Literal: "2"},
{Type: token.RBRACKET, Literal: "]"},
{Type: token.RBRACE, Literal: "}"},
{Type: token.RBRACE, Literal: "}"},
{Type: token.RBRACE, Literal: "}"},
{Type: token.RBRACE, Literal: "}"},
{Type: token.COMMA, Literal: ","},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.DOLLAR, Literal: "$"},
{Type: token.SYMBOL, Literal: "x"},
{Type: token.DOUBLE_QUOTE, Literal: "\""},
{Type: token.RBRACKET, Literal: "]"},
{Type: token.EOF, Literal: ""},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
l := New(tt.input)
for i, expected := range tt.expected {
tok := l.NextToken()
if tok.Type != expected.Type {
t.Fatalf("tests[%d] - tokentype wrong. expected=%q, got=%q", i, expected.Type, tok.Type)
}
if tok.Literal != expected.Literal {
t.Fatalf("tests[%d] - literal wrong. expected=%q, got=%q", i, expected.Literal, tok.Literal)
}
}
})
}
}
Loading

0 comments on commit 1fea968

Please sign in to comment.