github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/equity/compiler/parse.go (about)

     1  package compiler
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"fmt"
     7  	"strconv"
     8  	"unicode"
     9  )
    10  
    11  // We have some function naming conventions.
    12  //
    13  // For terminals:
    14  //   scanX     takes buf and position, returns new position (and maybe a value)
    15  //   peekX     takes *parser, returns bool or string
    16  //   consumeX  takes *parser and maybe a required literal, maybe returns value
    17  //             also updates the parser position
    18  //
    19  // For nonterminals:
    20  //   parseX    takes *parser, returns AST node, updates parser position
    21  
    22  type parser struct {
    23  	buf []byte
    24  	pos int
    25  }
    26  
    27  func (p *parser) errorf(format string, args ...interface{}) {
    28  	panic(parserErr{buf: p.buf, offset: p.pos, format: format, args: args})
    29  }
    30  
    31  // parse is the main entry point to the parser
    32  func parse(buf []byte) (contracts []*Contract, err error) {
    33  	defer func() {
    34  		if val := recover(); val != nil {
    35  			if e, ok := val.(parserErr); ok {
    36  				err = e
    37  			} else {
    38  				panic(val)
    39  			}
    40  		}
    41  	}()
    42  	p := &parser{buf: buf}
    43  	contracts = parseContracts(p)
    44  	return
    45  }
    46  
    47  // parse functions
    48  
    49  func parseContracts(p *parser) []*Contract {
    50  	var result []*Contract
    51  	if pos := scanKeyword(p.buf, p.pos, "contract"); pos < 0 {
    52  		p.errorf("expected contract")
    53  	}
    54  
    55  	for peekKeyword(p) == "contract" {
    56  		contract := parseContract(p)
    57  		result = append(result, contract)
    58  	}
    59  	return result
    60  }
    61  
    62  // contract name(p1, p2: t1, p3: t2) locks value { ... }
    63  func parseContract(p *parser) *Contract {
    64  	consumeKeyword(p, "contract")
    65  	name := consumeIdentifier(p)
    66  	params := parseParams(p)
    67  	// locks amount of asset
    68  	consumeKeyword(p, "locks")
    69  	value := ValueInfo{}
    70  	value.Amount = consumeIdentifier(p)
    71  	consumeKeyword(p, "of")
    72  	value.Asset = consumeIdentifier(p)
    73  	consumeTok(p, "{")
    74  	clauses := parseClauses(p)
    75  	consumeTok(p, "}")
    76  	return &Contract{Name: name, Params: params, Clauses: clauses, Value: value}
    77  }
    78  
    79  // (p1, p2: t1, p3: t2)
    80  func parseParams(p *parser) []*Param {
    81  	var params []*Param
    82  	consumeTok(p, "(")
    83  	first := true
    84  	for !peekTok(p, ")") {
    85  		if first {
    86  			first = false
    87  		} else {
    88  			consumeTok(p, ",")
    89  		}
    90  		pt := parseParamsType(p)
    91  		params = append(params, pt...)
    92  	}
    93  	consumeTok(p, ")")
    94  	return params
    95  }
    96  
    97  func parseClauses(p *parser) []*Clause {
    98  	var clauses []*Clause
    99  	for !peekTok(p, "}") {
   100  		c := parseClause(p)
   101  		clauses = append(clauses, c)
   102  	}
   103  	return clauses
   104  }
   105  
   106  func parseParamsType(p *parser) []*Param {
   107  	firstName := consumeIdentifier(p)
   108  	params := []*Param{&Param{Name: firstName}}
   109  	for peekTok(p, ",") {
   110  		consumeTok(p, ",")
   111  		name := consumeIdentifier(p)
   112  		params = append(params, &Param{Name: name})
   113  	}
   114  	consumeTok(p, ":")
   115  	typ := consumeIdentifier(p)
   116  	for _, parm := range params {
   117  		if tdesc, ok := types[typ]; ok {
   118  			parm.Type = tdesc
   119  		} else {
   120  			p.errorf("unknown type %s", typ)
   121  		}
   122  	}
   123  	return params
   124  }
   125  
   126  func parseClause(p *parser) *Clause {
   127  	var c Clause
   128  	consumeKeyword(p, "clause")
   129  	c.Name = consumeIdentifier(p)
   130  	c.Params = parseParams(p)
   131  	consumeTok(p, "{")
   132  	c.statements = parseStatements(p)
   133  	consumeTok(p, "}")
   134  	return &c
   135  }
   136  
   137  func parseStatements(p *parser) []statement {
   138  	var statements []statement
   139  	for !peekTok(p, "}") {
   140  		s := parseStatement(p)
   141  		statements = append(statements, s)
   142  	}
   143  	return statements
   144  }
   145  
   146  func parseStatement(p *parser) statement {
   147  	switch peekKeyword(p) {
   148  	case "if":
   149  		return parseIfStmt(p)
   150  	case "define":
   151  		return parseDefineStmt(p)
   152  	case "assign":
   153  		return parseAssignStmt(p)
   154  	case "verify":
   155  		return parseVerifyStmt(p)
   156  	case "lock":
   157  		return parseLockStmt(p)
   158  	case "unlock":
   159  		return parseUnlockStmt(p)
   160  	}
   161  	panic(parseErr(p.buf, p.pos, "unknown keyword \"%s\"", peekKeyword(p)))
   162  }
   163  
   164  func parseIfStmt(p *parser) *ifStatement {
   165  	consumeKeyword(p, "if")
   166  	condition := parseExpr(p)
   167  	body := &IfStatmentBody{}
   168  	consumeTok(p, "{")
   169  	body.trueBody = parseStatements(p)
   170  	consumeTok(p, "}")
   171  	if peekKeyword(p) == "else" {
   172  		consumeKeyword(p, "else")
   173  		consumeTok(p, "{")
   174  		body.falseBody = parseStatements(p)
   175  		consumeTok(p, "}")
   176  	}
   177  	return &ifStatement{condition: condition, body: body}
   178  }
   179  
   180  func parseDefineStmt(p *parser) *defineStatement {
   181  	defineStat := &defineStatement{}
   182  	consumeKeyword(p, "define")
   183  	param := &Param{}
   184  	param.Name = consumeIdentifier(p)
   185  	consumeTok(p, ":")
   186  	variableType := consumeIdentifier(p)
   187  	if tdesc, ok := types[variableType]; ok {
   188  		param.Type = tdesc
   189  	} else {
   190  		p.errorf("unknown type %s", variableType)
   191  	}
   192  	defineStat.variable = param
   193  	if peekTok(p, "=") {
   194  		consumeTok(p, "=")
   195  		defineStat.expr = parseExpr(p)
   196  	}
   197  	return defineStat
   198  }
   199  
   200  func parseAssignStmt(p *parser) *assignStatement {
   201  	consumeKeyword(p, "assign")
   202  	varName := consumeIdentifier(p)
   203  	consumeTok(p, "=")
   204  	expr := parseExpr(p)
   205  	return &assignStatement{variable: &Param{Name: varName}, expr: expr}
   206  }
   207  
   208  func parseVerifyStmt(p *parser) *verifyStatement {
   209  	consumeKeyword(p, "verify")
   210  	expr := parseExpr(p)
   211  	return &verifyStatement{expr: expr}
   212  }
   213  
   214  func parseLockStmt(p *parser) *lockStatement {
   215  	consumeKeyword(p, "lock")
   216  	lockedAmount := parseExpr(p)
   217  	consumeKeyword(p, "of")
   218  	lockedAsset := parseExpr(p)
   219  	consumeKeyword(p, "with")
   220  	program := parseExpr(p)
   221  	return &lockStatement{lockedAmount: lockedAmount, lockedAsset: lockedAsset, program: program}
   222  }
   223  
   224  func parseUnlockStmt(p *parser) *unlockStatement {
   225  	consumeKeyword(p, "unlock")
   226  	unlockedAmount := parseExpr(p)
   227  	consumeKeyword(p, "of")
   228  	unlockedAsset := parseExpr(p)
   229  	return &unlockStatement{unlockedAmount: unlockedAmount, unlockedAsset: unlockedAsset}
   230  }
   231  
   232  func parseExpr(p *parser) expression {
   233  	// Uses the precedence-climbing algorithm
   234  	// <https://en.wikipedia.org/wiki/Operator-precedence_parser#Precedence_climbing_method>
   235  	expr := parseUnaryExpr(p)
   236  	expr2, pos := parseExprCont(p, expr, 0)
   237  	if pos < 0 {
   238  		p.errorf("expected expression")
   239  	}
   240  	p.pos = pos
   241  	return expr2
   242  }
   243  
   244  func parseUnaryExpr(p *parser) expression {
   245  	op, pos := scanUnaryOp(p.buf, p.pos)
   246  	if pos < 0 {
   247  		return parseExpr2(p)
   248  	}
   249  	p.pos = pos
   250  	expr := parseUnaryExpr(p)
   251  	return &unaryExpr{op: op, expr: expr}
   252  }
   253  
   254  func parseExprCont(p *parser, lhs expression, minPrecedence int) (expression, int) {
   255  	for {
   256  		op, pos := scanBinaryOp(p.buf, p.pos)
   257  		if pos < 0 || op.precedence < minPrecedence {
   258  			break
   259  		}
   260  		p.pos = pos
   261  
   262  		rhs := parseUnaryExpr(p)
   263  
   264  		for {
   265  			op2, pos2 := scanBinaryOp(p.buf, p.pos)
   266  			if pos2 < 0 || op2.precedence <= op.precedence {
   267  				break
   268  			}
   269  			rhs, p.pos = parseExprCont(p, rhs, op2.precedence)
   270  			if p.pos < 0 {
   271  				return nil, -1 // or is this an error?
   272  			}
   273  		}
   274  		lhs = &binaryExpr{left: lhs, right: rhs, op: op}
   275  	}
   276  	return lhs, p.pos
   277  }
   278  
   279  func parseExpr2(p *parser) expression {
   280  	if expr, pos := scanLiteralExpr(p.buf, p.pos); pos >= 0 {
   281  		p.pos = pos
   282  		return expr
   283  	}
   284  	return parseExpr3(p)
   285  }
   286  
   287  func parseExpr3(p *parser) expression {
   288  	e := parseExpr4(p)
   289  	if peekTok(p, "(") {
   290  		args := parseArgs(p)
   291  		return &callExpr{fn: e, args: args}
   292  	}
   293  	return e
   294  }
   295  
   296  func parseExpr4(p *parser) expression {
   297  	if peekTok(p, "(") {
   298  		consumeTok(p, "(")
   299  		e := parseExpr(p)
   300  		consumeTok(p, ")")
   301  		return e
   302  	}
   303  	if peekTok(p, "[") {
   304  		var elts []expression
   305  		consumeTok(p, "[")
   306  		first := true
   307  		for !peekTok(p, "]") {
   308  			if first {
   309  				first = false
   310  			} else {
   311  				consumeTok(p, ",")
   312  			}
   313  			e := parseExpr(p)
   314  			elts = append(elts, e)
   315  		}
   316  		consumeTok(p, "]")
   317  		return listExpr(elts)
   318  	}
   319  	name := consumeIdentifier(p)
   320  	return varRef(name)
   321  }
   322  
   323  func parseArgs(p *parser) []expression {
   324  	var exprs []expression
   325  	consumeTok(p, "(")
   326  	first := true
   327  	for !peekTok(p, ")") {
   328  		if first {
   329  			first = false
   330  		} else {
   331  			consumeTok(p, ",")
   332  		}
   333  		e := parseExpr(p)
   334  		exprs = append(exprs, e)
   335  	}
   336  	consumeTok(p, ")")
   337  	return exprs
   338  }
   339  
   340  // peek functions
   341  
   342  func peekKeyword(p *parser) string {
   343  	name, _ := scanIdentifier(p.buf, p.pos)
   344  	return name
   345  }
   346  
   347  func peekTok(p *parser, token string) bool {
   348  	pos := scanTok(p.buf, p.pos, token)
   349  	return pos >= 0
   350  }
   351  
   352  // consume functions
   353  
   354  var keywords = []string{
   355  	"contract", "clause", "verify", "locks", "of",
   356  	"lock", "with", "unlock", "if", "else",
   357  	"define", "assign", "true", "false",
   358  }
   359  
   360  func consumeKeyword(p *parser, keyword string) {
   361  	pos := scanKeyword(p.buf, p.pos, keyword)
   362  	if pos < 0 {
   363  		p.errorf("expected keyword %s", keyword)
   364  	}
   365  	p.pos = pos
   366  }
   367  
   368  func consumeIdentifier(p *parser) string {
   369  	name, pos := scanIdentifier(p.buf, p.pos)
   370  	if pos < 0 {
   371  		p.errorf("expected identifier")
   372  	}
   373  	p.pos = pos
   374  	return name
   375  }
   376  
   377  func consumeTok(p *parser, token string) {
   378  	pos := scanTok(p.buf, p.pos, token)
   379  	if pos < 0 {
   380  		p.errorf("expected %s token", token)
   381  	}
   382  	p.pos = pos
   383  }
   384  
   385  // scan functions
   386  
   387  func scanUnaryOp(buf []byte, offset int) (*unaryOp, int) {
   388  	// Maximum munch. Make sure "-3" scans as ("-3"), not ("-", "3").
   389  	if _, pos := scanIntLiteral(buf, offset); pos >= 0 {
   390  		return nil, -1
   391  	}
   392  	for _, op := range unaryOps {
   393  		newOffset := scanTok(buf, offset, op.op)
   394  		if newOffset >= 0 {
   395  			return &op, newOffset
   396  		}
   397  	}
   398  	return nil, -1
   399  }
   400  
   401  func scanBinaryOp(buf []byte, offset int) (*binaryOp, int) {
   402  	offset = skipWsAndComments(buf, offset)
   403  	var (
   404  		found     *binaryOp
   405  		newOffset = -1
   406  	)
   407  	for i, op := range binaryOps {
   408  		offset2 := scanTok(buf, offset, op.op)
   409  		if offset2 >= 0 {
   410  			if found == nil || len(op.op) > len(found.op) {
   411  				found = &binaryOps[i]
   412  				newOffset = offset2
   413  			}
   414  		}
   415  	}
   416  	return found, newOffset
   417  }
   418  
   419  // TODO(bobg): boolean literals?
   420  func scanLiteralExpr(buf []byte, offset int) (expression, int) {
   421  	offset = skipWsAndComments(buf, offset)
   422  	intliteral, newOffset := scanIntLiteral(buf, offset)
   423  	if newOffset >= 0 {
   424  		return intliteral, newOffset
   425  	}
   426  	strliteral, newOffset := scanStrLiteral(buf, offset)
   427  	if newOffset >= 0 {
   428  		return strliteral, newOffset
   429  	}
   430  	bytesliteral, newOffset := scanBytesLiteral(buf, offset) // 0x6c249a...
   431  	if newOffset >= 0 {
   432  		return bytesliteral, newOffset
   433  	}
   434  	booleanLiteral, newOffset := scanBoolLiteral(buf, offset) // true or false
   435  	if newOffset >= 0 {
   436  		return booleanLiteral, newOffset
   437  	}
   438  	return nil, -1
   439  }
   440  
   441  func scanIdentifier(buf []byte, offset int) (string, int) {
   442  	offset = skipWsAndComments(buf, offset)
   443  	i := offset
   444  	for ; i < len(buf) && isIDChar(buf[i], i == offset); i++ {
   445  	}
   446  	if i == offset {
   447  		return "", -1
   448  	}
   449  	return string(buf[offset:i]), i
   450  }
   451  
   452  func scanTok(buf []byte, offset int, s string) int {
   453  	offset = skipWsAndComments(buf, offset)
   454  	prefix := []byte(s)
   455  	if bytes.HasPrefix(buf[offset:], prefix) {
   456  		return offset + len(prefix)
   457  	}
   458  	return -1
   459  }
   460  
   461  func scanKeyword(buf []byte, offset int, keyword string) int {
   462  	id, newOffset := scanIdentifier(buf, offset)
   463  	if newOffset < 0 {
   464  		return -1
   465  	}
   466  	if id != keyword {
   467  		return -1
   468  	}
   469  	return newOffset
   470  }
   471  
   472  func scanIntLiteral(buf []byte, offset int) (integerLiteral, int) {
   473  	offset = skipWsAndComments(buf, offset)
   474  	start := offset
   475  	if offset < len(buf) && buf[offset] == '-' {
   476  		offset++
   477  	}
   478  	i := offset
   479  	for ; i < len(buf) && unicode.IsDigit(rune(buf[i])); i++ {
   480  		// the literal is BytesLiteral when it starts with 0x/0X
   481  		if buf[i] == '0' && i < len(buf)-1 && (buf[i+1] == 'x' || buf[i+1] == 'X') {
   482  			return 0, -1
   483  		}
   484  	}
   485  	if i > offset {
   486  		n, err := strconv.ParseInt(string(buf[start:i]), 10, 64)
   487  		if err != nil {
   488  			return 0, -1
   489  		}
   490  		return integerLiteral(n), i
   491  	}
   492  	return 0, -1
   493  }
   494  
   495  func scanStrLiteral(buf []byte, offset int) (bytesLiteral, int) {
   496  	offset = skipWsAndComments(buf, offset)
   497  	if offset >= len(buf) || buf[offset] != '\'' {
   498  		return bytesLiteral{}, -1
   499  	}
   500  	var byteBuf bytesLiteral
   501  	for i := offset + 1; i < len(buf); i++ {
   502  		if buf[i] == '\'' {
   503  			return byteBuf, i + 1
   504  		}
   505  		if buf[i] == '\\' && i < len(buf)-1 {
   506  			if c, ok := scanEscape(buf[i+1]); ok {
   507  				byteBuf = append(byteBuf, c)
   508  				i++
   509  				continue
   510  			}
   511  		}
   512  		byteBuf = append(byteBuf, buf[i])
   513  	}
   514  	panic(parseErr(buf, offset, "unterminated string literal"))
   515  }
   516  
   517  func scanBytesLiteral(buf []byte, offset int) (bytesLiteral, int) {
   518  	offset = skipWsAndComments(buf, offset)
   519  	if offset+4 >= len(buf) {
   520  		return nil, -1
   521  	}
   522  	if buf[offset] != '0' || (buf[offset+1] != 'x' && buf[offset+1] != 'X') {
   523  		return nil, -1
   524  	}
   525  	if !isHexDigit(buf[offset+2]) || !isHexDigit(buf[offset+3]) {
   526  		return nil, -1
   527  	}
   528  	i := offset + 4
   529  	for ; i < len(buf); i += 2 {
   530  		if i == len(buf)-1 {
   531  			panic(parseErr(buf, offset, "odd number of digits in hex literal"))
   532  		}
   533  		if !isHexDigit(buf[i]) {
   534  			break
   535  		}
   536  		if !isHexDigit(buf[i+1]) {
   537  			panic(parseErr(buf, offset, "odd number of digits in hex literal"))
   538  		}
   539  	}
   540  	decoded := make([]byte, hex.DecodedLen(i-(offset+2)))
   541  	_, err := hex.Decode(decoded, buf[offset+2:i])
   542  	if err != nil {
   543  		return bytesLiteral{}, -1
   544  	}
   545  	return bytesLiteral(decoded), i
   546  }
   547  
   548  func scanBoolLiteral(buf []byte, offset int) (booleanLiteral, int) {
   549  	offset = skipWsAndComments(buf, offset)
   550  	if offset >= len(buf) {
   551  		return false, -1
   552  	}
   553  
   554  	newOffset := scanKeyword(buf, offset, "true")
   555  	if newOffset < 0 {
   556  		if newOffset = scanKeyword(buf, offset, "false"); newOffset < 0 {
   557  			return false, -1
   558  		}
   559  		return false, newOffset
   560  	}
   561  	return true, newOffset
   562  }
   563  
   564  func skipWsAndComments(buf []byte, offset int) int {
   565  	var inComment bool
   566  	for ; offset < len(buf); offset++ {
   567  		c := buf[offset]
   568  		if inComment {
   569  			if c == '\n' {
   570  				inComment = false
   571  			}
   572  		} else {
   573  			if c == '/' && offset < len(buf)-1 && buf[offset+1] == '/' {
   574  				inComment = true
   575  				offset++ // skip two chars instead of one
   576  			} else if !unicode.IsSpace(rune(c)) {
   577  				break
   578  			}
   579  		}
   580  	}
   581  	return offset
   582  }
   583  
   584  func isHexDigit(b byte) bool {
   585  	return (b >= '0' && b <= '9') || (b >= 'a' && b <= 'f') || (b >= 'A' && b <= 'F')
   586  }
   587  
   588  func isIDChar(c byte, initial bool) bool {
   589  	if c >= 'a' && c <= 'z' {
   590  		return true
   591  	}
   592  	if c >= 'A' && c <= 'Z' {
   593  		return true
   594  	}
   595  	if c == '_' {
   596  		return true
   597  	}
   598  	if initial {
   599  		return false
   600  	}
   601  	return unicode.IsDigit(rune(c))
   602  }
   603  
   604  type parserErr struct {
   605  	buf    []byte
   606  	offset int
   607  	format string
   608  	args   []interface{}
   609  }
   610  
   611  func parseErr(buf []byte, offset int, format string, args ...interface{}) error {
   612  	return parserErr{buf: buf, offset: offset, format: format, args: args}
   613  }
   614  
   615  func (p parserErr) Error() string {
   616  	// Lines start at 1, columns start at 0, like nature intended.
   617  	line := 1
   618  	col := 0
   619  	for i := 0; i < p.offset; i++ {
   620  		if p.buf[i] == '\n' {
   621  			line++
   622  			col = 0
   623  		} else {
   624  			col++
   625  		}
   626  	}
   627  	args := []interface{}{line, col}
   628  	args = append(args, p.args...)
   629  	return fmt.Sprintf("line %d, col %d: "+p.format, args...)
   630  }
   631  
   632  func scanEscape(c byte) (byte, bool) {
   633  	escapeFlag := true
   634  	switch c {
   635  	case '\'', '"', '\\':
   636  	case 'b':
   637  		c = '\b'
   638  	case 'f':
   639  		c = '\f'
   640  	case 'n':
   641  		c = '\n'
   642  	case 'r':
   643  		c = '\r'
   644  	case 't':
   645  		c = '\t'
   646  	case 'v':
   647  		c = '\v'
   648  	default:
   649  		escapeFlag = false
   650  	}
   651  	return c, escapeFlag
   652  }