aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2024-02-17 23:50:45 -0500
committerBobby <[email protected]>2024-02-17 23:50:45 -0500
commita18137bab2c53655168be9856e28de8c29232994 (patch)
tree9dc1ebbe8e49e97846f944a2e04e017f5dc267e6
parentb3d5ef5c6c3dcb6d1bf707b82e5350168d66d6c5 (diff)
downloadmana-a18137bab2c53655168be9856e28de8c29232994.tar.xz
mana-a18137bab2c53655168be9856e28de8c29232994.zip
Added Evaulator and Object Model
-rw-r--r--evaluator/evaluator.go34
-rw-r--r--evaluator/evaluator_test.go44
-rw-r--r--object/object.go52
-rw-r--r--repl/repl.go14
4 files changed, 139 insertions, 5 deletions
diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go
new file mode 100644
index 0000000..8d1b26d
--- /dev/null
+++ b/evaluator/evaluator.go
@@ -0,0 +1,34 @@
+package evaluator
+
+import (
+ "mana/ast"
+ "mana/object"
+)
+
+// Eval evaluates the given ast.Node and returns an object.Object.
+func Eval(node ast.Node) object.Object {
+ switch node := node.(type) {
+ // Statements
+ case *ast.Program:
+ return evalStatements(node.Statements)
+
+ case *ast.ExpressionStatement:
+ return Eval(node.Expression)
+
+ // Expressions
+ case *ast.IntegerLiteral:
+ return &object.Integer{Value: node.Value}
+ }
+
+ return nil
+}
+
+func evalStatements(stmts []ast.Statement) object.Object {
+ var result object.Object
+
+ for _, statement := range stmts {
+ result = Eval(statement)
+ }
+
+ return result
+}
diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go
new file mode 100644
index 0000000..cd1edb1
--- /dev/null
+++ b/evaluator/evaluator_test.go
@@ -0,0 +1,44 @@
+package evaluator
+
+import (
+ "mana/lexer"
+ "mana/object"
+ "mana/parser"
+
+ "testing"
+)
+
+func TestEvalIntegerExpression(t *testing.T) {
+ tests := []struct {
+ input string
+ expected int64
+ }{
+ {"5", 5},
+ {"10", 10},
+ }
+
+ for _, tt := range tests {
+ evalated := testEval(tt.input)
+ testIntegerObject(t, evalated, tt.expected)
+ }
+}
+
+func testEval(input string) object.Object {
+ l := lexer.New(input)
+ p := parser.New(l)
+ program := p.ParseProgram()
+ return Eval(program)
+}
+
+func testIntegerObject(t *testing.T, obj object.Object, expected int64) bool {
+ result, ok := obj.(*object.Integer)
+ if !ok {
+ t.Errorf("object is not Integer. got=%T (%+v)", obj, obj)
+ return false
+ }
+ if result.Value != expected {
+ t.Errorf("object has wrong value. got=%d, want=%d", result.Value, expected)
+ return false
+ }
+ return true
+}
diff --git a/object/object.go b/object/object.go
new file mode 100644
index 0000000..cac36ac
--- /dev/null
+++ b/object/object.go
@@ -0,0 +1,52 @@
+package object
+
+import "fmt"
+
+type ObjectType string
+
+const (
+ INTEGER_OBJ = "INTEGER"
+ BOOLEAN_OBJ = "BOOLEAN"
+ NULL_OBJ = "NULL"
+)
+
+type Object interface {
+ Type() ObjectType
+ Inspect() string
+}
+
+type Integer struct {
+ Value int64
+}
+
+type Boolean struct {
+ Value bool
+}
+
+type Null struct{}
+
+func (i *Integer) Type() ObjectType {
+ return INTEGER_OBJ
+}
+
+func (i *Integer) Inspect() string {
+ return fmt.Sprintf("%d", i.Value)
+}
+
+func (b *Boolean) Type() ObjectType {
+ return BOOLEAN_OBJ
+}
+
+func (b *Boolean) Inspect() string {
+ return fmt.Sprintf("%t", b.Value)
+}
+
+func (n *Null) Type() ObjectType {
+ return NULL_OBJ
+}
+
+func (n *Null) Inspect() string {
+ return "null"
+}
+
+
diff --git a/repl/repl.go b/repl/repl.go
index 9db9683..9a43119 100644
--- a/repl/repl.go
+++ b/repl/repl.go
@@ -6,11 +6,12 @@ import (
"io"
"mana/lexer"
"mana/parser"
+ "mana/evaluator"
)
// PROMPT is the prompt for the REPL.
const PROMPT = ">>> "
-const MANA_ICON = `
+const MANA_START = `
███╗░░░███╗░█████╗░███╗░░██╗░█████╗░
████╗░████║██╔══██╗████╗░██║██╔══██╗
██╔████╔██║███████║██╔██╗██║███████║
@@ -21,7 +22,7 @@ const MANA_ICON = `
func Start(in io.Reader, out io.Writer) {
var scanner *bufio.Scanner = bufio.NewScanner(in)
- io.WriteString(out, MANA_ICON + "\n")
+ io.WriteString(out, MANA_START + "\n")
for {
fmt.Fprint(out, PROMPT)
@@ -42,13 +43,16 @@ func Start(in io.Reader, out io.Writer) {
continue
}
- io.WriteString(out, program.String())
- io.WriteString(out, "\n")
+ evaluated := evaluator.Eval(program)
+ if evaluated != nil {
+ io.WriteString(out, evaluated.Inspect())
+ io.WriteString(out, "\n")
+ }
}
}
func printParserErrors(out io.Writer, errors []string) {
- io.WriteString(out, "Mana Encountered Parser Errors:\n")
+ io.WriteString(out, "ParseError:\n")
for _, msg := range errors {
io.WriteString(out, "\t" + msg + "\n")
}