diff options
author | wmin0 <wmin0@cobinhood.com> | 2019-01-17 15:51:56 +0800 |
---|---|---|
committer | Jhih-Ming Huang <jm.huang@cobinhood.com> | 2019-05-06 10:44:03 +0800 |
commit | 1c850cdf326ce37a98ad25cb3c42442ca1eec907 (patch) | |
tree | e0cb8e42ccbc4c9dc019e322ca99ab54feb42cd2 /core/vm/sqlvm/grammar.peg | |
parent | 9b8cd76237318e173147a7c32763b6b9d9759951 (diff) | |
download | dexon-1c850cdf326ce37a98ad25cb3c42442ca1eec907.tar dexon-1c850cdf326ce37a98ad25cb3c42442ca1eec907.tar.gz dexon-1c850cdf326ce37a98ad25cb3c42442ca1eec907.tar.bz2 dexon-1c850cdf326ce37a98ad25cb3c42442ca1eec907.tar.lz dexon-1c850cdf326ce37a98ad25cb3c42442ca1eec907.tar.xz dexon-1c850cdf326ce37a98ad25cb3c42442ca1eec907.tar.zst dexon-1c850cdf326ce37a98ad25cb3c42442ca1eec907.zip |
core: vm: sqlvm: add sql language parser prototyping
Add sql language parser prototyping along with
1. grammar file implemented with github.com/mna/pigeon
2. ast node struct definition
3. simple parser test which only test if error existed
4. ast printer utility for visualizing parsing result
Diffstat (limited to 'core/vm/sqlvm/grammar.peg')
-rw-r--r-- | core/vm/sqlvm/grammar.peg | 763 |
1 files changed, 763 insertions, 0 deletions
diff --git a/core/vm/sqlvm/grammar.peg b/core/vm/sqlvm/grammar.peg new file mode 100644 index 000000000..ac2f8928c --- /dev/null +++ b/core/vm/sqlvm/grammar.peg @@ -0,0 +1,763 @@ +{ +package sqlvm +} + +S + <- _ x:Stmt? _ xs:( ';' _ s:Stmt? _ { return s, nil } )* EOF +{ return prepend(x, xs), nil } + +/* statement */ +Stmt + = SelectStmt + / UpdateStmt + / DeleteStmt + / InsertStmt + / CreateTableStmt + / CreateIndexStmt + +SelectStmt + = SelectToken + _ f:SelectColumn fs:( _ SeparatorToken _ s:SelectColumn { return s, nil } )* + table:( _ FromToken _ i:Identifier { return i, nil } )? + where:( _ w:WhereClause { return w, nil } )? + group:( _ g:GroupByClause { return g, nil } )? + order:( _ or:OrderByClause { return or, nil } )? + limit:( _ l:LimitClause { return l, nil } )? + offset:( _ of:OffsetClause { return of, nil } )? +{ + var ( + tableNode *identifierNode + whereNode *whereOptionNode + limitNode *limitOptionNode + offsetNode *offsetOptionNode + ) + if table != nil { + t := table.(identifierNode) + tableNode = &t + } + if where != nil { + w := where.(whereOptionNode) + whereNode = &w + } + if limit != nil { + l := limit.(limitOptionNode) + limitNode = &l + } + if offset != nil { + of := offset.(offsetOptionNode) + offsetNode = &of + } + return selectStmtNode{ + column: prepend(f, fs), + table: tableNode, + where: whereNode, + group: toSlice(group), + order: toSlice(order), + limit: limitNode, + offset: offsetNode, + }, nil +} + +SelectColumn + = AnyLiteral + / Expr + +UpdateStmt + = UpdateToken + _ table:Identifier + _ SetToken + _ a:Assignment as:( _ SeparatorToken _ s:Assignment { return s, nil } )* + where:( _ w:WhereClause { return w, nil } )? +{ + var ( + whereNode *whereOptionNode + ) + if where != nil { + w := where.(whereOptionNode) + whereNode = &w + } + return updateStmtNode{ + table: table.(identifierNode), + assignment: prepend(a, as), + where: whereNode, + }, nil +} + +DeleteStmt + = DeleteToken + _ FromToken + _ table:Identifier + where:( _ w:WhereClause { return w, nil } )? +{ + var ( + whereNode *whereOptionNode + ) + if where != nil { + w := where.(whereOptionNode) + whereNode = &w + } + return deleteStmtNode{ + table: table.(identifierNode), + where: whereNode, + }, nil +} + +InsertStmt + = InsertToken + _ IntoToken + _ table:Identifier + _ insert:( InsertWithColumnClause / InsertWithDefaultClause ) +{ + return insertStmtNode{ + table: table.(identifierNode), + insert: insert, + }, nil +} + +InsertValue + = '(' _ e:MultiExprWithDefault _ ')' +{ return e, nil } + +CreateTableStmt + = CreateToken + _ TableToken + _ table:Identifier + _ '(' + _ column:( + s:ColumnSchema + ss:( _ SeparatorToken _ t:ColumnSchema { return t, nil } )* + { return prepend(s, ss), nil } + )? + _ ')' +{ + return createTableStmtNode{ + table: table.(identifierNode), + column: toSlice(column), + }, nil +} + +ColumnSchema + = i:Identifier + _ t:DataType + cs:( _ s:ColumnConstraint { return s, nil } )* +{ + return columnSchemaNode{ + column: i.(identifierNode), + dataType: t, + constraint: toSlice(cs), + }, nil +} + +ColumnConstraint + = PrimaryKeyClause + / NotNullClause + / UniqueClause + / DefaultClause + / ForeignClause + / AutoincrementClause + +CreateIndexStmt + = CreateToken + unique:( _ u:UniqueClause { return u, nil } )? + _ IndexToken + _ index:Identifier + _ OnToken + _ table:Identifier + _ '(' _ i:Identifier is:( _ SeparatorToken _ x:Identifier { return x, nil } )* _ ')' +{ + var ( + uniqueNode *uniqueOptionNode + ) + if unique != nil { + u := unique.(uniqueOptionNode) + uniqueNode = &u + } + return createIndexStmtNode{ + index: index.(identifierNode), + table: table.(identifierNode), + column: prepend(i, is), + unique: uniqueNode, + }, nil +} + +/* clause */ +WhereClause + = WhereToken _ e:Expr +{ return whereOptionNode{condition: e}, nil } + +OrderByClause + = OrderToken + _ ByToken + _ f:OrderColumn + fs:( _ SeparatorToken _ s:OrderColumn { return s, nil } )* +{ return prepend(f, fs), nil } + +OrderColumn + = i:Expr + s:( _ t:( AscToken / DescToken ) { return t, nil } )? + n:( _ NullsToken _ l:( LastToken / FirstToken ) { return l, nil } )? +{ + return orderOptionNode{ + expr: i, + desc: s != nil && string(s.([]byte)) == "desc", + nullfirst: n != nil && string(n.([]byte)) == "first", + }, nil +} + +GroupByClause + = GroupToken + _ ByToken + _ i:Expr + is:( _ SeparatorToken _ s:Expr { return groupOptionNode{expr: s}, nil } )* +{ return prepend(groupOptionNode{expr: i}, is), nil } + +OffsetClause + = OffsetToken _ i:Integer +{ return offsetOptionNode{value: i.(integerValueNode)}, nil } + +LimitClause + = LimitToken _ i:Integer +{ return limitOptionNode{value: i.(integerValueNode)}, nil } + +InsertWithColumnClause + = cs:( '(' + _ f:Identifier + fs:( _ SeparatorToken _ x:Identifier { return x, nil } )* + _ ')' + _ { return prepend(f, fs), nil } + )? + ValuesToken + _ v:InsertValue + vs:( _ SeparatorToken _ y:InsertValue { return y, nil } )* +{ + return insertWithColumnOptionNode{ + column: toSlice(cs), + value: prepend(v, vs), + }, nil +} + +InsertWithDefaultClause + = DefaultToken _ ValuesToken +{ return insertWithDefaultOptionNode{}, nil } + +PrimaryKeyClause + = PrimaryToken _ KeyToken +{ return primaryOptionNode{}, nil } + +NotNullClause + = NotToken _ NullToken +{ return notNullOptionNode{}, nil } + +UniqueClause + = UniqueToken +{ return uniqueOptionNode{}, nil } + +DefaultClause + = DefaultToken _ e:Expr +{ return defaultOptionNode{value: e}, nil } + +ForeignClause + = ReferencesToken _ t:Identifier _ '(' _ f:Identifier _ ')' +{ + return foreignOptionNode{ + table: t.(identifierNode), + column: f.(identifierNode), + }, nil +} + +AutoincrementClause + = AutoincrementToken +{ return autoincrementOptionNode{}, nil } + +/* expression */ +Expr + = LogicExpr + +ExprWithDefault + = &(DefaultLiteral) d:DefaultLiteral { return d, nil } + / Expr + +LogicExpr + = LogicExpr4 + +LogicExpr4 + = o:LogicExpr3 + os:( _ op:OrOperator _ s:LogicExpr3 { return opSetSubject(op, s), nil } )* +{ return rightJoinOperators(o, os), nil } + +LogicExpr3 + = o:LogicExpr2 + os:( _ op:AndOperator _ s:LogicExpr2 { return opSetSubject(op, s), nil } )* +{ return rightJoinOperators(o, os), nil } + +LogicExpr2 + = op:NotOperator _ s:LogicExpr2 + { return opSetTarget(op, s), nil } + / LogicExpr1 + +LogicExpr1 + = o:ArithmeticExpr os:( _ l:LogicExpr1Op { return l, nil } )* +{ return rightJoinOperators(o, os), nil } + +LogicExpr1Op + = LogicExpr1In + / LogicExpr1Null + / LogicExpr1Like + / LogicExpr1Cmp + +LogicExpr1In + = n:( t:NotOperator _ { return t, nil } )? InToken _ '(' _ s:MultiExpr _ ')' +{ + op := opSetSubject(&inOperatorNode{}, s) + if n != nil { + return opSetTarget(n, op), nil + } + return op, nil +} + +LogicExpr1Null + = IsToken n:( _ t:NotOperator { return t, nil } )? _ NullToken +{ + op := opSetSubject(&isOperatorNode{}, nullValueNode{}) + if n != nil { + return opSetTarget(n, op), nil + } + return op, nil +} + +LogicExpr1Like + = n:( t:NotOperator _ { return t, nil } )? LikeToken _ s:Expr +{ + op := opSetSubject(&likeOperatorNode{}, s) + if n != nil { + return opSetTarget(n, op), nil + } + return op, nil +} + +LogicExpr1Cmp + = op:CmpOperator _ s:ArithmeticExpr +{ return opSetSubject(op, s), nil } + +ArithmeticExpr + = ArithmeticExpr3 + +ArithmeticExpr3 + = o:ArithmeticExpr2 os:( _ op:ConcatOperator _ s:ArithmeticExpr2 { return opSetSubject(op, s), nil } )* +{ return rightJoinOperators(o, os), nil } + +ArithmeticExpr2 + = o:ArithmeticExpr1 os:( _ op:AddSubOperator _ s:ArithmeticExpr1 { return opSetSubject(op, s), nil } )* +{ return rightJoinOperators(o, os), nil } + +ArithmeticExpr1 + = o:Operand os:( _ op:MulDivModOperator _ s:Operand { return opSetSubject(op, s), nil } )* +{ return rightJoinOperators(o, os), nil } + +MultiExpr + = x:Expr xs:( _ SeparatorToken _ e:Expr { return e, nil } )* +{ return prepend(x, xs), nil } + +MultiExprWithDefault + = x:ExprWithDefault xs:( _ SeparatorToken _ e:ExprWithDefault { return e, nil } )* +{ return prepend(x, xs), nil } + +Operand + = op:UnaryOperator _ s:Operand { return opSetTarget(op, s), nil } + / '(' _ e:Expr _ ')' { return e, nil } + / &(CastToken) t:TypeCast { return t, nil } + / FunctionCall + / Value + / Identifier + +TypeCast + = CastToken _ '(' _ o:Expr _ AsToken _ s:DataType _ ')' +{ return opSetSubject(opSetObject(&castOperatorNode{}, o), s), nil } + +FunctionCall + = i:Identifier _ '(' _ r:FunctionArgs? _ ')' +{ return opSetSubject(opSetObject(&functionOperatorNode{}, i), r), nil } + +FunctionArgs + = a:AnyLiteral { return []interface{}{a}, nil } + / MultiExpr + +Assignment + = i:Identifier _ '=' _ e:ExprWithDefault +{ return opSetSubject(opSetObject(&assignOperatorNode{}, i), e), nil } + +/* operator */ +UnaryOperator + = SignOperator + +SignOperator + = Sign +{ + switch string(c.text) { + case "+": + return &posOperatorNode{}, nil + case "-": + return &negOperatorNode{}, nil + } + return nil, errors.New("unknown sign") +} + +NotOperator + = NotToken +{ return ¬OperatorNode{}, nil } + +AndOperator + = AndToken +{ return &andOperatorNode{}, nil } + +OrOperator + = OrToken +{ return &orOperatorNode{}, nil } + +CmpOperator + = ( "<=" / ">=" / "<>" / "!=" / [<>=] ) +{ + switch string(c.text) { + case "<=": + return &lessOrEqualOperatorNode{}, nil + case ">=": + return &greaterOrEqualOperatorNode{}, nil + case "<>": + return ¬EqualOperatorNode{}, nil + case "!=": + return ¬EqualOperatorNode{}, nil + case "<": + return &lessOperatorNode{}, nil + case ">": + return &greaterOperatorNode{}, nil + case "=": + return &equalOperatorNode{}, nil + } + return nil, errors.New("unknown cmp") +} + +ConcatOperator + = "||" +{ return &concatOperatorNode{}, nil } + +AddSubOperator + = [+-] +{ + switch string(c.text) { + case "+": + return &addOperatorNode{}, nil + case "-": + return &subOperatorNode{}, nil + } + return nil, errors.New("unknown add sub") +} + +MulDivModOperator + = [*/%] +{ + switch string(c.text) { + case "*": + return &mulOperatorNode{}, nil + case "/": + return &divOperatorNode{}, nil + case "%": + return &modOperatorNode{}, nil + } + return nil, errors.New("unknown mul div mod") +} + +/* type */ +DataType + = UIntType + / IntType + / UFixedType + / FixedType + / FixedBytesType + / DynamicBytesType + / BoolType + / AddressType + +UIntType + = "UINT"i s:NonZeroLeadingInteger !NormalIdentifierRest +{ return intTypeNode{size: toInt(s.([]byte)), unsigned: true}, nil } + +IntType + = "INT"i s:NonZeroLeadingInteger !NormalIdentifierRest +{ return intTypeNode{size: toInt(s.([]byte))}, nil } + +UFixedType + = "UFIXED"i s:NonZeroLeadingInteger "X"i t:NonZeroLeadingInteger !NormalIdentifierRest +{ + return fixedTypeNode{ + integerSize: toInt(s.([]byte)), + fractionalSize: toInt(t.([]byte)), + unsigned: true, + }, nil +} + +FixedType + = "FIXED"i s:NonZeroLeadingInteger "X"i t:NonZeroLeadingInteger !NormalIdentifierRest +{ + return fixedTypeNode{ + integerSize: toInt(s.([]byte)), + fractionalSize: toInt(t.([]byte)), + }, nil +} + +FixedBytesType + = "BYTES"i s:NonZeroLeadingInteger !NormalIdentifierRest +{ return fixedBytesTypeNode{size: toInt(s.([]byte))}, nil } + / "BYTE"i !NormalIdentifierRest +{ return fixedBytesTypeNode{size: 1}, nil } + +DynamicBytesType + = ( "BYTES"i !NormalIdentifierRest + / "STRING"i !NormalIdentifierRest + / "TEXT"i !NormalIdentifierRest + ) +{ return dynamicBytesTypeNode{}, nil } + +AddressType + = "ADDRESS"i !NormalIdentifierRest +{ return addressTypeNode{}, nil } + +BoolType + = ( "BOOL"i !NormalIdentifierRest + / "BOOLEAN"i !NormalIdentifierRest + ) +{ return boolTypeNode{}, nil } + +/* value */ +Value + = NumberLiteral + / StringLiteral + / BoolLiteral + / NullLiteral + +AnyLiteral + = AnyToken +{ return anyValueNode{}, nil } + +DefaultLiteral + = DefaultToken +{ return defaultValueNode{}, nil } + +BoolLiteral + = b:( TrueToken / FalseToken ) +{ return boolValueNode(string(b.([]byte)) == "true"), nil } + +NullLiteral + = NullToken +{ return nullValueNode{}, nil } + +NumberLiteral + = &("0" "X"i) h:Hex { return h, nil } + / Decimal + +Sign + = [-+] + +Integer + = [0-9]+ +{ return integerValueNode{v: toDecimal(c.text)}, nil } + +NonZeroLeadingInteger + = ( "0" / [1-9][0-9]* ) +{ return c.text, nil } + +Fixnum + = Integer "." Integer + / Integer "."? + / "." Integer + +Decimal + = Fixnum ( "E"i Sign? Integer )? +{ return decimalValueNode(toDecimal(c.text)), nil } + +Hex + = "0" "X"i s:( [0-9A-Fa-f] )+ !NormalIdentifierRest +{ return hexToInteger(joinBytes(s)), nil } + +StringLiteral + = HexString + / NormalString + +HexString + = ( "HEX"i / "X"i ) "'" s:([0-9a-fA-F][0-9a-fA-F] { return c.text, nil } )* "'" +{ return bytesValueNode(hexToBytes(joinBytes(s))), nil } + +NormalString + = "'" s:( ( [^'\r\n\\] / "\\" . ) { return c.text, nil } )* "'" +{ return bytesValueNode(resolveString(joinBytes(s))), nil } + +/* token */ +SelectToken + = "SELECT"i !NormalIdentifierRest + +FromToken + = "FROM"i !NormalIdentifierRest + +WhereToken + = "WHERE"i !NormalIdentifierRest + +OrderToken + = "ORDER"i !NormalIdentifierRest + +ByToken + = "BY"i !NormalIdentifierRest + +GroupToken + = "GROUP"i !NormalIdentifierRest + +LimitToken + = "LIMIT"i !NormalIdentifierRest + +OffsetToken + = "OFFSET"i !NormalIdentifierRest + +UpdateToken + = "UPDATE"i !NormalIdentifierRest + +SetToken + = "SET"i !NormalIdentifierRest + +DeleteToken + = "DELETE"i !NormalIdentifierRest + +InsertToken + = "INSERT"i !NormalIdentifierRest + +IntoToken + = "INTO"i !NormalIdentifierRest + +ValuesToken + = "VALUES"i !NormalIdentifierRest + +CreateToken + = "CREATE"i !NormalIdentifierRest + +TableToken + = "TABLE"i !NormalIdentifierRest + +IndexToken + = "INDEX"i !NormalIdentifierRest + +UniqueToken + = "UNIQUE"i !NormalIdentifierRest + +DefaultToken + = "DEFAULT"i !NormalIdentifierRest + +PrimaryToken + = "PRIMARY"i !NormalIdentifierRest + +KeyToken + = "KEY"i !NormalIdentifierRest + +ReferencesToken + = "REFERENCES"i !NormalIdentifierRest + +AutoincrementToken + = "AUTOINCREMENT"i !NormalIdentifierRest + +OnToken + = "ON"i !NormalIdentifierRest + +TrueToken + = "TRUE"i !NormalIdentifierRest +{ return toLower(c.text), nil } + +FalseToken + = "FALSE"i !NormalIdentifierRest +{ return toLower(c.text), nil } + +NullToken + = "NULL"i !NormalIdentifierRest + +IsToken + = "IS"i !NormalIdentifierRest + +NullsToken + = "NULLS"i !NormalIdentifierRest + +LastToken + = "LAST"i !NormalIdentifierRest +{ return toLower(c.text), nil } + +FirstToken + = "FIRST"i !NormalIdentifierRest +{ return toLower(c.text), nil } + +AndToken + = "AND"i !NormalIdentifierRest + +OrToken + = "OR"i !NormalIdentifierRest + +NotToken + = "NOT"i !NormalIdentifierRest + +InToken + = "IN"i !NormalIdentifierRest + +LikeToken + = "LIKE"i !NormalIdentifierRest + +AscToken + = "ASC"i !NormalIdentifierRest +{ return toLower(c.text), nil } + +DescToken + = "DESC"i !NormalIdentifierRest +{ return toLower(c.text), nil } + +CastToken + = "CAST"i !NormalIdentifierRest + +AsToken + = "AS"i !NormalIdentifierRest + +SeparatorToken + = "," + +AnyToken + = "*" + +/* identifier */ +Identifier + = NormalIdentifier + / StringIdentifier + +NormalIdentifier + = NormalIdentifierStart NormalIdentifierRest* +{ return identifierNode(c.text), nil } + +NormalIdentifierStart + = [a-zA-Z@#_\u0080-\uffff] + +NormalIdentifierRest + = [a-zA-Z0-9@#$_\u0080-\uffff] + +StringIdentifier + = "\"" s:( ( [^"\r\n\\] / "\\" . ) { return c.text, nil } )* "\"" +{ + return identifierNode(resolveString(joinBytes(s))), nil +} + +/* skip */ +_ + = ( Whitespace / Newline )* + +Newline + = "\r\n" + / "\r" + / "\n" + +Whitespace + = " " + / "\t" + / "\v" + / "\f" + +EOF + = !. |