selectors support for hash
Some checks failed
Build / build (push) Successful in 10m20s
Test / build (push) Failing after 16m7s

This commit is contained in:
Chuck Smith
2024-03-21 16:39:31 -04:00
parent d3471af03d
commit 66d5453ecc
8 changed files with 98 additions and 2 deletions

View File

@@ -577,6 +577,36 @@ func TestHashLiterals(t *testing.T) {
}
}
func TestHashSelectorExpressions(t *testing.T) {
tests := []struct {
input string
expected interface{}
}{
{
`{"foo": 5}.foo`,
5,
},
{
`{"foo": 5}.bar`,
nil,
},
{
`{}.foo`,
nil,
},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
integer, ok := tt.expected.(int)
if ok {
testIntegerObject(t, evaluated, int64(integer))
} else {
testNullObject(t, evaluated)
}
}
}
func TestHashIndexExpressions(t *testing.T) {
tests := []struct {
input string

View File

@@ -0,0 +1,5 @@
let d = {"foo": 1, "bar": 2}
assert(d.foo == 1, "d.foo != 1")
assert(d.bar == 2, "d.bar != 2")
assert(d.bogus == null, "d.bogus != null")

View File

@@ -107,6 +107,8 @@ func (l *Lexer) NextToken() token.Token {
tok = newToken(token.SEMICOLON, l.ch)
case ',':
tok = newToken(token.COMMA, l.ch)
case '.':
tok = newToken(token.DOT, l.ch)
case '(':
tok = newToken(token.LPAREN, l.ch)
case ')':

View File

@@ -32,7 +32,7 @@ func TestNextToken(t *testing.T) {
"foo bar"
[1, 2];
{"foo": "bar"}
"foo \"bar\""
d.foo
`
tests := []struct {
@@ -138,7 +138,9 @@ func TestNextToken(t *testing.T) {
{token.COLON, ":"},
{token.STRING, "bar"},
{token.RBRACE, "}"},
{token.STRING, "foo \"bar\""},
{token.IDENT, "d"},
{token.DOT, "."},
{token.IDENT, "foo"},
{token.EOF, ""},
}

View File

@@ -35,6 +35,7 @@ var precedences = map[token.TokenType]int{
token.ASTERISK: PRODUCT,
token.LPAREN: CALL,
token.LBRACKET: INDEX,
token.DOT: INDEX,
}
type (
@@ -89,6 +90,7 @@ func New(l *lexer.Lexer) *Parser {
p.registerInfix(token.LPAREN, p.parseCallExpression)
p.registerInfix(token.LBRACKET, p.parseIndexExpression)
p.registerInfix(token.ASSIGN, p.parseAssignmentExpression)
p.registerInfix(token.DOT, p.parseSelectorExpression)
// Read two tokens, so curToken and peekToken are both set
p.nextToken()
@@ -570,3 +572,9 @@ func (p *Parser) parseComment() ast.Statement {
func (p *Parser) parseNull() ast.Expression {
return &ast.Null{Token: p.curToken}
}
func (p *Parser) parseSelectorExpression(expression ast.Expression) ast.Expression {
p.expectPeek(token.IDENT)
index := &ast.StringLiteral{Token: p.curToken, Value: p.curToken.Literal}
return &ast.IndexExpression{Left: expression, Index: index}
}

View File

@@ -358,6 +358,10 @@ func TestOperatorPrecedenceParsing(t *testing.T) {
"add(a * b[2], b[1], 2 * [1, 2][1])",
"add((a * (b[2])), (b[1]), (2 * ([1, 2][1])))",
},
{
"d.foo * d.bar",
"((d[foo]) * (d[bar]))",
},
}
for _, tt := range tests {
@@ -831,6 +835,40 @@ func TestParsingArrayLiterals(t *testing.T) {
testInfixExpression(t, array.Elements[2], 3, "+", 3)
}
func TestParsingSelectorExpressions(t *testing.T) {
input := "myHash.foo"
l := lexer.New(input)
p := New(l)
program := p.ParseProgram()
checkParserErrors(t, p)
stmt, ok := program.Statements[0].(*ast.ExpressionStatement)
t.Logf("stmt: %#v", stmt)
exp, ok := stmt.Expression.(*ast.IndexExpression)
if !ok {
t.Fatalf("exp not *ast.IndexExpression. got=%T", stmt.Expression)
}
ident, ok := exp.Left.(*ast.Identifier)
if !ok {
t.Fatalf("exp.Left not *ast.Identifier. got=%T", stmt.Expression)
}
if !testIdentifier(t, ident, "myHash") {
return
}
index, ok := exp.Index.(*ast.StringLiteral)
if !ok {
t.Fatalf("exp.Index not *ast.StringLiteral. got=%T", stmt.Expression)
}
if index.Value != "foo" {
t.Fatalf("index.Value != \"foo\"")
}
}
func TestParsingIndexExpressions(t *testing.T) {
input := "myArray[1 + 1]"

View File

@@ -39,6 +39,7 @@ const (
COMMA = ","
SEMICOLON = ";"
COLON = ":"
DOT = "."
LPAREN = "("
RPAREN = ")"

View File

@@ -328,6 +328,16 @@ func TestHashLiterals(t *testing.T) {
runVmTests(t, tests)
}
func TestSelectorExpressions(t *testing.T) {
tests := []vmTestCase{
{`{"foo": 5}.foo`, 5},
{`{"foo": 5}.bar`, nil},
{`{}.foo`, nil},
}
runVmTests(t, tests)
}
func TestIndexExpressions(t *testing.T) {
tests := []vmTestCase{
{"[1, 2, 3][1]", 2},