Beispiel #1
0
func (p *Parser) expression() (node *tp.Instruction) {
	terms := tp.ListInstructions(p.term())
	for p.peek().Lexeme == PLUS {
		p.pop() // pop the plus sign
		switch p.peek().Lexeme {
		case STRING, REGEXP, POS, READ, ID, TYPE, GVAR, LVAR, LPAREN:
			rhs := p.term()
			last := len(terms) - 1
			if terms[last].GetType() == constants.Instruction_TEXT && rhs.GetType() == constants.Instruction_TEXT {
				terms[last] = tp.MakeText(terms[last].GetValue()+rhs.GetValue(), terms[last].GetLineNumber())
			} else {
				terms = append(terms, rhs)
			}
		default:
			p.error("argument to `+` must be a self-contained expression")
		}
	}
	if len(terms) > 1 {
		node = tp.FoldLeft("concat", terms[0], terms[1:len(terms)])
	} else {
		node = terms[0]
	}
	return node
}
Beispiel #2
0
func (p *Parser) call(funcName *Token) (node *tp.Instruction) {
	funcNameStr := funcName.Value // grab the function name
	funcLineNo := funcName.LineNumber
	if p.peek().Lexeme != LPAREN {
		p.error("parenthesized argument list expected in call to " + funcNameStr)
	}
	p.pop() // pop the lparen

	ords, kwdnames, kwdvals := p.arguments(funcNameStr) // gather the arguments
	numArgs := len(ords)

	// this will never happen because p.arguments() only returns when it encounters an rparen
	if p.peek().Lexeme != RPAREN {
		p.error("unterminated argument list in call to " + funcNameStr)
	}
	p.pop() // pop the rparen
	var block []*tp.Instruction
	if p.peek().Lexeme == LBRACE {
		block = p.block()
	}

	// Expand keyword args
	if kwdnames != nil && kwdvals != nil {
		kwdToGensym := make(map[string]string, len(kwdnames))
		outer := tp.ListInstructions()
		for i, k := range kwdnames {
			tempname := p.gensym()
			tempvar := tp.MakeFunctionCall("var",
				tp.ListInstructions(tp.MakeText(tempname, funcLineNo),
					kwdvals[i]),
				nil, funcLineNo)
			outer = append(outer, tempvar)
			kwdToGensym[k] = tempname
		}
		inner := tp.ListInstructions()
		for _, k := range kwdnames {
			getter := tp.MakeFunctionCall("var",
				tp.ListInstructions(tp.MakeText(kwdToGensym[k], funcLineNo)),
				nil, funcLineNo)
			setter := tp.MakeFunctionCall("set",
				tp.ListInstructions(tp.MakeText(k, funcLineNo), getter),
				nil, funcLineNo)
			inner = append(inner, setter)
		}
		if block != nil {
			for _, v := range block {
				inner = append(inner, v)
			}
		}
		theCall := tp.MakeFunctionCall(funcNameStr, ords, inner, funcLineNo)
		outer = append(outer, theCall)
		node = tp.MakeBlock(outer, funcLineNo)

	} else if funcNameStr == "concat" && numArgs > 2 {
		// expand variadic concat into nested binary concats
		lhs := tp.FoldLeft("concat", ords[0], ords[1:numArgs-1])
		rhs := ords[numArgs-1]
		node = tp.MakeFunctionCall("concat", tp.ListInstructions(lhs, rhs), block, funcLineNo)
	} else if funcNameStr == "log" && numArgs > 1 {
		// expand variadic log into composition of log and concat
		cats := tp.FoldLeft("concat", ords[0], ords[1:])
		node = tp.MakeFunctionCall("log", tp.ListInstructions(cats), block, funcLineNo)
	} else {
		node = tp.MakeFunctionCall(funcNameStr, ords, block, funcLineNo)
	}
	// if it's not a root file, we can assume that it's a user-called function
	if !p.CompilingMixer /* p.RootFile == false && IncludeSelectorInfo == true */ {
		node.IsUserCalled = proto.Bool(true)
	}
	return node
}