blob: 04374753edf80b40a584ea59b200bdd346ce4b0d [file] [log] [blame]
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package parser
import (
neturl "net/url"
"android.googlesource.com/platform/tools/gpu/api/ast"
"android.googlesource.com/platform/tools/gpu/parse"
)
// lhs { extend } [class_initializer]
func requireExpression(p *parse.Parser, cst *parse.Branch) interface{} {
lhs := requireLHSExpression(p, cst)
for {
if e := extendExpression(p, cst, lhs); e != nil {
lhs = e
} else {
if l, ok := lhs.(*ast.Identifier); ok && peekOperator(ast.OpBlockStart, p) {
lhs = requireClassInitializer(p, cst, l)
}
break
}
}
return lhs
}
// lhs { extend }
func requireSimpleExpression(p *parse.Parser, cst *parse.Branch) interface{} {
lhs := requireLHSExpression(p, cst)
for {
if e := extendExpression(p, cst, lhs); e != nil {
lhs = e
} else {
break
}
}
return lhs
}
// ( group | switch | new | length | literal | unary_op | identifier)
func requireLHSExpression(p *parse.Parser, cst *parse.Branch) interface{} {
if g := group(p, cst); g != nil {
return g
}
if s := switch_(p, cst); s != nil {
return s
}
if n := new(p, cst); n != nil {
return n
}
if l := length(p, cst); l != nil {
return l
}
if l := literal(p, cst); l != nil {
return l
}
if u := unaryOp(p, cst); u != nil {
return u
}
if i := identifier(p, cst); i != nil {
return i
}
p.Expected("expression")
return &ast.Invalid{}
}
// lhs (index | call | cast | binary_op | member)
func extendExpression(p *parse.Parser, cst *parse.Branch, lhs interface{}) interface{} {
if i := index(p, cst, lhs); i != nil {
return i
}
if c := call(p, cst, lhs); c != nil {
return c
}
if c := cast(p, cst, lhs); c != nil {
return c
}
if e := binaryOp(p, cst, lhs); e != nil {
return e
}
if m := member(p, cst, lhs); m != nil {
return m
}
return nil
}
// classname '{' { fieldname : expression [ ',' ] } '}'
func requireClassInitializer(p *parse.Parser, cst *parse.Branch, class *ast.Identifier) *ast.ClassInitializer {
e := &ast.ClassInitializer{Class: class}
p.ParseBranch(cst, func(p *parse.Parser, cst *parse.Branch) {
e.CST = cst
requireOperator(ast.OpBlockStart, p, cst)
for !operator(ast.OpBlockEnd, p, cst) {
p.ParseBranch(cst, func(p *parse.Parser, cst *parse.Branch) {
entry := &ast.FieldInitializer{}
entry.CST = cst
entry.Name = requireIdentifier(p, cst)
requireOperator(ast.OpInitialise, p, cst)
entry.Value = requireExpression(p, cst)
operator(ast.OpListSeparator, p, cst)
e.Fields = append(e.Fields, entry)
})
}
})
return e
}
// 'true' | 'false' | '"' string '"' | '?' | number
func literal(p *parse.Parser, cst *parse.Branch) interface{} {
if l := keyword(ast.KeywordTrue, p, cst); l != nil {
return &ast.Bool{CST: l, Value: true}
}
if l := keyword(ast.KeywordFalse, p, cst); l != nil {
return &ast.Bool{CST: l, Value: false}
}
if p.Rune(ast.Quote) {
n := &ast.String{}
p.ParseLeaf(cst, func(p *parse.Parser, l *parse.Leaf) {
n.CST = l
p.SeekRune(ast.Quote)
p.Rune(ast.Quote)
l.SetToken(p.Consume())
v := l.Token().String()
n.Value = v[1 : len(v)-1]
})
return n
}
if peekOperator(ast.OpUnknown, p) {
n := &ast.Unknown{}
p.ParseLeaf(cst, func(p *parse.Parser, l *parse.Leaf) {
n.CST = l
requireOperator(ast.OpUnknown, p, cst)
})
return n
}
if n := number(p, cst); n != nil {
return n
}
return nil
}
// standard numeric formats
func number(p *parse.Parser, cst *parse.Branch) *ast.Number {
_ = p.Rune('+') || p.Rune('-') // optional sign
if p.Numeric() == parse.NotNumeric {
p.Rollback()
return nil
}
n := &ast.Number{}
p.ParseLeaf(cst, func(p *parse.Parser, l *parse.Leaf) { n.CST = l })
n.Value = n.CST.Token().String()
return n
}
func requireNumber(p *parse.Parser, cst *parse.Branch) *ast.Number {
n := number(p, cst)
if n == nil {
p.Expected("number")
}
return n
}
// 'http://' notspace
func url(p *parse.Parser, cst *parse.Branch) *ast.URL {
if !p.String("http://") {
return nil
}
p.NotSpace()
n := &ast.URL{}
p.ParseLeaf(cst, func(p *parse.Parser, l *parse.Leaf) {
n.CST = l
l.SetToken(p.Consume())
v, err := neturl.Parse(l.Token().String())
if err != nil {
p.Expected("http url")
} else {
n.URL = *v
}
})
return n
}
// '(' expression ')'
func group(p *parse.Parser, cst *parse.Branch) *ast.Group {
if !peekOperator(ast.OpListStart, p) {
return nil
}
e := &ast.Group{}
p.ParseBranch(cst, func(p *parse.Parser, cst *parse.Branch) {
e.CST = cst
requireOperator(ast.OpListStart, p, cst)
e.Expression = requireExpression(p, cst)
requireOperator(ast.OpListEnd, p, cst)
})
return e
}
// switch '{' { 'case' { expresion } ':' block } '}'
func switch_(p *parse.Parser, cst *parse.Branch) *ast.Switch {
if !peekKeyword(ast.KeywordSwitch, p) {
return nil
}
e := &ast.Switch{}
p.ParseBranch(cst, func(p *parse.Parser, cst *parse.Branch) {
e.CST = cst
requireKeyword(ast.KeywordSwitch, p, cst)
e.Value = requireExpression(p, cst)
requireOperator(ast.OpBlockStart, p, cst)
for !operator(ast.OpBlockEnd, p, cst) {
p.ParseBranch(cst, func(p *parse.Parser, cst *parse.Branch) {
entry := &ast.Case{}
entry.CST = cst
requireKeyword(ast.KeywordCase, p, cst)
for !operator(ast.OpExtends, p, cst) {
if len(entry.Conditions) > 0 {
requireOperator(ast.OpListSeparator, p, cst)
}
entry.Conditions = append(entry.Conditions, requireExpression(p, cst))
}
entry.Block = requireBlock(p, cst)
e.Cases = append(e.Cases, entry)
})
}
})
return e
}
// 'new' class_initializer
func new(p *parse.Parser, cst *parse.Branch) *ast.New {
if !peekKeyword(ast.KeywordNew, p) {
return nil
}
e := &ast.New{}
p.ParseBranch(cst, func(p *parse.Parser, cst *parse.Branch) {
e.CST = cst
requireKeyword(ast.KeywordNew, p, cst)
class := requireIdentifier(p, cst)
e.ClassInitializer = requireClassInitializer(p, cst, class)
})
return e
}
// 'len' '(' expression ')'
func length(p *parse.Parser, cst *parse.Branch) *ast.Length {
if !peekKeyword(ast.KeywordLength, p) {
return nil
}
s := &ast.Length{}
p.ParseBranch(cst, func(p *parse.Parser, cst *parse.Branch) {
s.CST = cst
requireKeyword(ast.KeywordLength, p, cst)
requireOperator(ast.OpListStart, p, cst)
s.Object = requireExpression(p, cst)
requireOperator(ast.OpListEnd, p, cst)
})
return s
}
// lhs '[' expression ']'
func index(p *parse.Parser, cst *parse.Branch, lhs interface{}) *ast.Index {
if !peekOperator(ast.OpIndexStart, p) {
return nil
}
e := &ast.Index{Object: lhs}
p.ParseBranch(cst, func(p *parse.Parser, cst *parse.Branch) {
e.CST = cst
requireOperator(ast.OpIndexStart, p, cst)
e.Index = requireExpression(p, cst)
requireOperator(ast.OpIndexEnd, p, cst)
})
return e
}
// lhs '(' [ expression { ',' expression } ] ')'
func call(p *parse.Parser, cst *parse.Branch, lhs interface{}) *ast.Call {
if !peekOperator(ast.OpListStart, p) {
return nil
}
e := &ast.Call{Target: lhs}
p.ParseBranch(cst, func(p *parse.Parser, cst *parse.Branch) {
e.CST = cst
requireOperator(ast.OpListStart, p, cst)
for !operator(ast.OpListEnd, p, cst) {
if len(e.Arguments) > 0 {
requireOperator(ast.OpListSeparator, p, cst)
}
e.Arguments = append(e.Arguments, requireExpression(p, cst))
}
})
return e
}
// lhs 'as' type
func cast(p *parse.Parser, cst *parse.Branch, lhs interface{}) *ast.Cast {
if !peekKeyword(ast.KeywordAs, p) {
return nil
}
e := &ast.Cast{Object: lhs}
p.ParseBranch(cst, func(p *parse.Parser, cst *parse.Branch) {
e.CST = cst
requireKeyword(ast.KeywordAs, p, cst)
e.Type = requireTypeRef(p, cst)
})
return e
}
// lhs '.' identifier
func member(p *parse.Parser, cst *parse.Branch, lhs interface{}) *ast.Member {
if !peekOperator(ast.OpMember, p) {
return nil
}
e := &ast.Member{Object: lhs}
p.ParseBranch(cst, func(p *parse.Parser, cst *parse.Branch) {
e.CST = cst
requireOperator(ast.OpMember, p, cst)
e.Name = requireIdentifier(p, cst)
})
return e
}