191 lines
5.2 KiB
Go
191 lines
5.2 KiB
Go
package parser_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"git.sharkk.net/Sharkk/Mako/parser"
|
|
)
|
|
|
|
func TestAssignStatements(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
expectedIdentifier string
|
|
expectedValue any
|
|
isExpression bool
|
|
}{
|
|
{"x = 42", "x", 42.0, false},
|
|
{"name = \"test\"", "name", "test", false},
|
|
{"flag = true", "flag", true, false},
|
|
{"ptr = nil", "ptr", nil, false},
|
|
{"result = 3 + 4", "result", "(3.00 + 4.00)", true},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.input, func(t *testing.T) {
|
|
l := parser.NewLexer(tt.input)
|
|
p := parser.NewParser(l)
|
|
program := p.ParseProgram()
|
|
checkParserErrors(t, p)
|
|
|
|
if len(program.Statements) != 1 {
|
|
t.Fatalf("expected 1 statement, got %d", len(program.Statements))
|
|
}
|
|
|
|
stmt, ok := program.Statements[0].(*parser.Assignment)
|
|
if !ok {
|
|
t.Fatalf("expected Assignment, got %T", program.Statements[0])
|
|
}
|
|
|
|
// Check that Target is an Identifier
|
|
ident, ok := stmt.Target.(*parser.Identifier)
|
|
if !ok {
|
|
t.Fatalf("expected Identifier for Target, got %T", stmt.Target)
|
|
}
|
|
|
|
if ident.Value != tt.expectedIdentifier {
|
|
t.Errorf("expected identifier %s, got %s", tt.expectedIdentifier, ident.Value)
|
|
}
|
|
|
|
if tt.isExpression {
|
|
if stmt.Value.String() != tt.expectedValue.(string) {
|
|
t.Errorf("expected expression %s, got %s", tt.expectedValue.(string), stmt.Value.String())
|
|
}
|
|
} else {
|
|
switch expected := tt.expectedValue.(type) {
|
|
case float64:
|
|
testNumberLiteral(t, stmt.Value, expected)
|
|
case string:
|
|
testStringLiteral(t, stmt.Value, expected)
|
|
case bool:
|
|
testBooleanLiteral(t, stmt.Value, expected)
|
|
case nil:
|
|
testNilLiteral(t, stmt.Value)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMemberAccessAssignment(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
expected string
|
|
description string
|
|
}{
|
|
{"table.key = 42", "table.key = 42.00", "dot notation assignment"},
|
|
{"arr[1] = \"hello\"", "arr[1.00] = \"hello\"", "bracket notation assignment"},
|
|
{"obj.nested.deep = true", "obj.nested.deep = true", "chained dot assignment"},
|
|
{"matrix[1][2] = 3.14", "matrix[1.00][2.00] = 3.14", "chained bracket assignment"},
|
|
{"data[\"key\"].value = nil", "data[\"key\"].value = nil", "mixed access assignment"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.description, func(t *testing.T) {
|
|
l := parser.NewLexer(tt.input)
|
|
p := parser.NewParser(l)
|
|
program := p.ParseProgram()
|
|
checkParserErrors(t, p)
|
|
|
|
if len(program.Statements) != 1 {
|
|
t.Fatalf("expected 1 statement, got %d", len(program.Statements))
|
|
}
|
|
|
|
stmt, ok := program.Statements[0].(*parser.Assignment)
|
|
if !ok {
|
|
t.Fatalf("expected Assignment, got %T", program.Statements[0])
|
|
}
|
|
|
|
if stmt.String() != tt.expected {
|
|
t.Errorf("expected %s, got %s", tt.expected, stmt.String())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMemberAccessExpressions(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
expected string
|
|
description string
|
|
}{
|
|
{"echo table.key", "echo table.key", "dot access"},
|
|
{"echo arr[1]", "echo arr[1.00]", "bracket access"},
|
|
{"echo obj.nested.deep", "echo obj.nested.deep", "chained dot access"},
|
|
{"echo matrix[1][2]", "echo matrix[1.00][2.00]", "chained bracket access"},
|
|
{"echo data[\"key\"].value", "echo data[\"key\"].value", "mixed access"},
|
|
{"echo table.key + arr[0]", "echo (table.key + arr[0.00])", "member access in expression"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.description, func(t *testing.T) {
|
|
l := parser.NewLexer(tt.input)
|
|
p := parser.NewParser(l)
|
|
program := p.ParseProgram()
|
|
checkParserErrors(t, p)
|
|
|
|
if len(program.Statements) != 1 {
|
|
t.Fatalf("expected 1 statement, got %d", len(program.Statements))
|
|
}
|
|
|
|
if program.Statements[0].String() != tt.expected {
|
|
t.Errorf("expected %s, got %s", tt.expected, program.Statements[0].String())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTableAssignments(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
identifier string
|
|
pairCount int
|
|
isArray bool
|
|
description string
|
|
}{
|
|
{"arr = {1, 2, 3}", "arr", 3, true, "array assignment"},
|
|
{"hash = {x = 1, y = 2}", "hash", 2, false, "hash assignment"},
|
|
{"empty = {}", "empty", 0, true, "empty table assignment"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.description, func(t *testing.T) {
|
|
l := parser.NewLexer(tt.input)
|
|
p := parser.NewParser(l)
|
|
program := p.ParseProgram()
|
|
checkParserErrors(t, p)
|
|
|
|
if len(program.Statements) != 1 {
|
|
t.Fatalf("expected 1 statement, got %d", len(program.Statements))
|
|
}
|
|
|
|
stmt, ok := program.Statements[0].(*parser.Assignment)
|
|
if !ok {
|
|
t.Fatalf("expected Assignment, got %T", program.Statements[0])
|
|
}
|
|
|
|
// Check that Target is an Identifier
|
|
ident, ok := stmt.Target.(*parser.Identifier)
|
|
if !ok {
|
|
t.Fatalf("expected Identifier for Target, got %T", stmt.Target)
|
|
}
|
|
|
|
if ident.Value != tt.identifier {
|
|
t.Errorf("expected identifier %s, got %s", tt.identifier, ident.Value)
|
|
}
|
|
|
|
table, ok := stmt.Value.(*parser.TableLiteral)
|
|
if !ok {
|
|
t.Fatalf("expected TableLiteral, got %T", stmt.Value)
|
|
}
|
|
|
|
if len(table.Pairs) != tt.pairCount {
|
|
t.Errorf("expected %d pairs, got %d", tt.pairCount, len(table.Pairs))
|
|
}
|
|
|
|
if table.IsArray() != tt.isArray {
|
|
t.Errorf("expected IsArray() = %t, got %t", tt.isArray, table.IsArray())
|
|
}
|
|
})
|
|
}
|
|
}
|