config/lang: more implemented

This commit is contained in:
Mitchell Hashimoto 2015-01-11 13:03:37 -08:00
parent fcdcf117f0
commit 669bdc61f9
8 changed files with 262 additions and 70 deletions

7
config/lang/ast/call.go Normal file
View File

@ -0,0 +1,7 @@
package ast
// Call represents a function call.
type Call struct {
Func string
Args []Node
}

View File

@ -1,6 +1,14 @@
package ast package ast
import (
"fmt"
)
// VariableAccess represents a variable access. // VariableAccess represents a variable access.
type VariableAccess struct { type VariableAccess struct {
Name string Name string
} }
func (n *VariableAccess) GoString() string {
return fmt.Sprintf("*%#v", *n)
}

View File

@ -12,13 +12,16 @@ import (
%} %}
%union { %union {
node ast.Node node ast.Node
str string nodeList []ast.Node
str string
} }
%token <str> STRING IDENTIFIER PROGRAM_BRACKET_LEFT PROGRAM_BRACKET_RIGHT %token <str> STRING IDENTIFIER PROGRAM_BRACKET_LEFT PROGRAM_BRACKET_RIGHT
%token <str> PAREN_LEFT PAREN_RIGHT COMMA
%type <node> expr interpolation literal %type <node> expr interpolation literal
%type <nodeList> args
%% %%
@ -27,6 +30,10 @@ top:
{ {
parserResult = $1 parserResult = $1
} }
| interpolation
{
parserResult = $1
}
| literal interpolation | literal interpolation
{ {
parserResult = &ast.Concat{ parserResult = &ast.Concat{
@ -41,14 +48,31 @@ interpolation:
} }
expr: expr:
IDENTIFIER literal
{
$$ = &ast.VariableAccess{Name: $1}
}
| literal
{ {
$$ = $1 $$ = $1
} }
| IDENTIFIER
{
$$ = &ast.VariableAccess{Name: $1}
}
| IDENTIFIER PAREN_LEFT args PAREN_RIGHT
{
$$ = &ast.Call{Func: $1, Args: $3}
}
args:
{
$$ = nil
}
| args COMMA expr
{
$$ = append($1, $3)
}
| expr
{
$$ = append($$, $1)
}
literal: literal:
STRING STRING

View File

@ -38,9 +38,21 @@ func (x *parserLex) Lex(yylval *parserSymType) int {
return PROGRAM_BRACKET_LEFT return PROGRAM_BRACKET_LEFT
} }
if x.interpolationDepth == 0 {
// We're just a normal string that isn't part of any
// interpolation yet.
x.backup()
return x.lexString(yylval, false)
}
// Ignore all whitespace
if unicode.IsSpace(c) {
continue
}
// If we see a double quote and we're in an interpolation, then // If we see a double quote and we're in an interpolation, then
// we are lexing a string. // we are lexing a string.
if c == '"' && x.interpolationDepth > 0 { if c == '"' {
return x.lexString(yylval, true) return x.lexString(yylval, true)
} }
@ -48,16 +60,15 @@ func (x *parserLex) Lex(yylval *parserSymType) int {
case '}': case '}':
x.interpolationDepth-- x.interpolationDepth--
return PROGRAM_BRACKET_RIGHT return PROGRAM_BRACKET_RIGHT
case '(':
return PAREN_LEFT
case ')':
return PAREN_RIGHT
case ',':
return COMMA
default: default:
x.backup() x.backup()
if x.interpolationDepth > 0 { return x.lexId(yylval)
// We're within an interpolation.
return x.lexId(yylval)
} else {
// We're just a normal string that isn't part of any
// interpolation yet.
return x.lexString(yylval, false)
}
} }
} }
} }

View File

@ -29,6 +29,22 @@ func TestLex(t *testing.T) {
"foo ${\"bar\"}", "foo ${\"bar\"}",
[]int{STRING, PROGRAM_BRACKET_LEFT, STRING, PROGRAM_BRACKET_RIGHT, lexEOF}, []int{STRING, PROGRAM_BRACKET_LEFT, STRING, PROGRAM_BRACKET_RIGHT, lexEOF},
}, },
{
"${bar(baz)}",
[]int{PROGRAM_BRACKET_LEFT,
IDENTIFIER, PAREN_LEFT, IDENTIFIER, PAREN_RIGHT,
PROGRAM_BRACKET_RIGHT, lexEOF},
},
{
"${bar(baz, foo)}",
[]int{PROGRAM_BRACKET_LEFT,
IDENTIFIER, PAREN_LEFT,
IDENTIFIER, COMMA, IDENTIFIER,
PAREN_RIGHT,
PROGRAM_BRACKET_RIGHT, lexEOF},
},
} }
for _, tc := range cases { for _, tc := range cases {

View File

@ -54,6 +54,35 @@ func TestParse(t *testing.T) {
}, },
}, },
}, },
{
"${foo(bar)}",
false,
&ast.Call{
Func: "foo",
Args: []ast.Node{
&ast.VariableAccess{
Name: "bar",
},
},
},
},
{
"${foo(bar, baz)}",
false,
&ast.Call{
Func: "foo",
Args: []ast.Node{
&ast.VariableAccess{
Name: "bar",
},
&ast.VariableAccess{
Name: "baz",
},
},
},
},
} }
for _, tc := range cases { for _, tc := range cases {

View File

@ -10,21 +10,28 @@ import (
//line lang.y:14 //line lang.y:14
type parserSymType struct { type parserSymType struct {
yys int yys int
node ast.Node node ast.Node
str string nodeList []ast.Node
str string
} }
const STRING = 57346 const STRING = 57346
const IDENTIFIER = 57347 const IDENTIFIER = 57347
const PROGRAM_BRACKET_LEFT = 57348 const PROGRAM_BRACKET_LEFT = 57348
const PROGRAM_BRACKET_RIGHT = 57349 const PROGRAM_BRACKET_RIGHT = 57349
const PAREN_LEFT = 57350
const PAREN_RIGHT = 57351
const COMMA = 57352
var parserToknames = []string{ var parserToknames = []string{
"STRING", "STRING",
"IDENTIFIER", "IDENTIFIER",
"PROGRAM_BRACKET_LEFT", "PROGRAM_BRACKET_LEFT",
"PROGRAM_BRACKET_RIGHT", "PROGRAM_BRACKET_RIGHT",
"PAREN_LEFT",
"PAREN_RIGHT",
"COMMA",
} }
var parserStatenames = []string{} var parserStatenames = []string{}
@ -32,7 +39,7 @@ const parserEofCode = 1
const parserErrCode = 2 const parserErrCode = 2
const parserMaxDepth = 200 const parserMaxDepth = 200
//line lang.y:59 //line lang.y:83
//line yacctab:1 //line yacctab:1
var parserExca = []int{ var parserExca = []int{
@ -41,41 +48,47 @@ var parserExca = []int{
-2, 0, -2, 0,
} }
const parserNprod = 7 const parserNprod = 12
const parserPrivate = 57344 const parserPrivate = 57344
var parserTokenNames []string var parserTokenNames []string
var parserStates []string var parserStates []string
const parserLast = 10 const parserLast = 18
var parserAct = []int{ var parserAct = []int{
9, 3, 7, 2, 5, 3, 1, 4, 6, 8, 7, 14, 15, 11, 10, 4, 5, 5, 4, 9,
3, 1, 13, 6, 8, 2, 16, 12,
} }
var parserPact = []int{ var parserPact = []int{
1, -1000, -2, -1000, -1000, -3, -7, -1000, -1000, -1000, 1, -1000, 0, -1000, -1000, 4, -1000, -3, -1000, -5,
-1000, 4, -8, -1000, -1000, 4, -1000,
} }
var parserPgo = []int{ var parserPgo = []int{
0, 8, 7, 3, 6, 0, 0, 10, 14, 17, 11,
} }
var parserR1 = []int{ var parserR1 = []int{
0, 4, 4, 2, 1, 1, 3, 0, 5, 5, 5, 2, 1, 1, 1, 4, 4,
4, 3,
} }
var parserR2 = []int{ var parserR2 = []int{
0, 1, 2, 3, 1, 1, 1, 0, 1, 1, 2, 3, 1, 1, 4, 0, 3,
1, 1,
} }
var parserChk = []int{ var parserChk = []int{
-1000, -4, -3, 4, -2, 6, -1, 5, -3, 7, -1000, -5, -3, -2, 4, 6, -2, -1, -3, 5,
7, 8, -4, -1, 9, 10, -1,
} }
var parserDef = []int{ var parserDef = []int{
0, -2, 1, 6, 2, 0, 0, 4, 5, 3, 0, -2, 1, 2, 11, 0, 3, 0, 5, 6,
4, 8, 0, 10, 7, 0, 9,
} }
var parserTok1 = []int{ var parserTok1 = []int{
@ -83,7 +96,7 @@ var parserTok1 = []int{
} }
var parserTok2 = []int{ var parserTok2 = []int{
2, 3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 7, 8, 9, 10,
} }
var parserTok3 = []int{ var parserTok3 = []int{
0, 0,
@ -315,34 +328,59 @@ parserdefault:
switch parsernt { switch parsernt {
case 1: case 1:
//line lang.y:27 //line lang.y:30
{ {
parserResult = parserS[parserpt-0].node parserResult = parserS[parserpt-0].node
} }
case 2: case 2:
//line lang.y:31 //line lang.y:34
{
parserResult = parserS[parserpt-0].node
}
case 3:
//line lang.y:38
{ {
parserResult = &ast.Concat{ parserResult = &ast.Concat{
Exprs: []ast.Node{parserS[parserpt-1].node, parserS[parserpt-0].node}, Exprs: []ast.Node{parserS[parserpt-1].node, parserS[parserpt-0].node},
} }
} }
case 3: case 4:
//line lang.y:39 //line lang.y:46
{ {
parserVAL.node = parserS[parserpt-1].node parserVAL.node = parserS[parserpt-1].node
} }
case 4:
//line lang.y:45
{
parserVAL.node = &ast.VariableAccess{Name: parserS[parserpt-0].str}
}
case 5: case 5:
//line lang.y:49 //line lang.y:52
{ {
parserVAL.node = parserS[parserpt-0].node parserVAL.node = parserS[parserpt-0].node
} }
case 6: case 6:
//line lang.y:55 //line lang.y:56
{
parserVAL.node = &ast.VariableAccess{Name: parserS[parserpt-0].str}
}
case 7:
//line lang.y:60
{
parserVAL.node = &ast.Call{Func: parserS[parserpt-3].str, Args: parserS[parserpt-1].nodeList}
}
case 8:
//line lang.y:65
{
parserVAL.nodeList = nil
}
case 9:
//line lang.y:69
{
parserVAL.nodeList = append(parserS[parserpt-2].nodeList, parserS[parserpt-0].node)
}
case 10:
//line lang.y:73
{
parserVAL.nodeList = append(parserVAL.nodeList, parserS[parserpt-0].node)
}
case 11:
//line lang.y:79
{ {
parserVAL.node = &ast.LiteralNode{Value: parserS[parserpt-0].str, Type: ast.TypeString} parserVAL.node = &ast.LiteralNode{Value: parserS[parserpt-0].str, Type: ast.TypeString}
} }

View File

@ -2,9 +2,11 @@
state 0 state 0
$accept: .top $end $accept: .top $end
STRING shift 3 STRING shift 4
PROGRAM_BRACKET_LEFT shift 5
. error . error
interpolation goto 3
literal goto 2 literal goto 2
top goto 1 top goto 1
@ -20,66 +22,123 @@ state 2
top: literal.interpolation top: literal.interpolation
PROGRAM_BRACKET_LEFT shift 5 PROGRAM_BRACKET_LEFT shift 5
. reduce 1 (src line 25) . reduce 1 (src line 28)
interpolation goto 4 interpolation goto 6
state 3 state 3
literal: STRING. (6) top: interpolation. (2)
. reduce 6 (src line 53) . reduce 2 (src line 33)
state 4 state 4
top: literal interpolation. (2) literal: STRING. (11)
. reduce 2 (src line 30) . reduce 11 (src line 77)
state 5 state 5
interpolation: PROGRAM_BRACKET_LEFT.expr PROGRAM_BRACKET_RIGHT interpolation: PROGRAM_BRACKET_LEFT.expr PROGRAM_BRACKET_RIGHT
STRING shift 3 STRING shift 4
IDENTIFIER shift 7 IDENTIFIER shift 9
. error . error
expr goto 6 expr goto 7
literal goto 8 literal goto 8
state 6 state 6
interpolation: PROGRAM_BRACKET_LEFT expr.PROGRAM_BRACKET_RIGHT top: literal interpolation. (3)
PROGRAM_BRACKET_RIGHT shift 9 . reduce 3 (src line 37)
. error
state 7 state 7
expr: IDENTIFIER. (4) interpolation: PROGRAM_BRACKET_LEFT expr.PROGRAM_BRACKET_RIGHT
. reduce 4 (src line 43) PROGRAM_BRACKET_RIGHT shift 10
. error
state 8 state 8
expr: literal. (5) expr: literal. (5)
. reduce 5 (src line 48) . reduce 5 (src line 50)
state 9 state 9
interpolation: PROGRAM_BRACKET_LEFT expr PROGRAM_BRACKET_RIGHT. (3) expr: IDENTIFIER. (6)
expr: IDENTIFIER.PAREN_LEFT args PAREN_RIGHT
. reduce 3 (src line 37) PAREN_LEFT shift 11
. reduce 6 (src line 55)
7 terminals, 5 nonterminals state 10
7 grammar rules, 10/2000 states interpolation: PROGRAM_BRACKET_LEFT expr PROGRAM_BRACKET_RIGHT. (4)
. reduce 4 (src line 44)
state 11
expr: IDENTIFIER PAREN_LEFT.args PAREN_RIGHT
args: . (8)
STRING shift 4
IDENTIFIER shift 9
. reduce 8 (src line 64)
expr goto 13
literal goto 8
args goto 12
state 12
expr: IDENTIFIER PAREN_LEFT args.PAREN_RIGHT
args: args.COMMA expr
PAREN_RIGHT shift 14
COMMA shift 15
. error
state 13
args: expr. (10)
. reduce 10 (src line 72)
state 14
expr: IDENTIFIER PAREN_LEFT args PAREN_RIGHT. (7)
. reduce 7 (src line 59)
state 15
args: args COMMA.expr
STRING shift 4
IDENTIFIER shift 9
. error
expr goto 16
literal goto 8
state 16
args: args COMMA expr. (9)
. reduce 9 (src line 68)
10 terminals, 6 nonterminals
12 grammar rules, 17/2000 states
0 shift/reduce, 0 reduce/reduce conflicts reported 0 shift/reduce, 0 reduce/reduce conflicts reported
54 working sets used 55 working sets used
memory: parser 5/30000 memory: parser 11/30000
1 extra closures 6 extra closures
5 shift entries, 1 exceptions 13 shift entries, 1 exceptions
5 goto entries 9 goto entries
0 entries saved by goto default 2 entries saved by goto default
Optimizer space used: output 10/30000 Optimizer space used: output 18/30000
10 table entries, 0 zero 18 table entries, 0 zero
maximum spread: 7, maximum offset: 7 maximum spread: 10, maximum offset: 15