Example #1
0
func (p *Parser) literal() (node *tp.Instruction) {
	token := p.pop()
	switch token.Lexeme {
	case STRING:
		node = tp.MakeText(token.Value, token.LineNumber)
	case REGEXP:
		node = tp.MakeFunctionCall("regexp",
			tp.ListInstructions(tp.MakeText(token.Value, token.LineNumber),
				tp.MakeText(token.ExtraValue, token.LineNumber)),
			nil,
			token.LineNumber)
	case POS:
		node = tp.MakePosition(token.Value, token.LineNumber)
	}
	return node
}
Example #2
0
func (p *Parser) cast(typeName *Token) (node *tp.Instruction) {
	typeNameStr := typeName.Value // grab the function name
	typeLineNo := typeName.LineNumber
	if p.peek().Lexeme != LPAREN {
		p.error("parenthesized argument needed for typecast to " + typeNameStr)
	}
	p.pop() // pop the lparen
	expr := p.expression()
	if p.peek().Lexeme != RPAREN {
		p.error("single argument to " + typeNameStr + " typecast is missing closing parenthesis")
	}
	p.pop() // pop the rparen
	var block []*tp.Instruction
	if p.peek().Lexeme == LBRACE {
		block = p.block()
	}

	node = tp.MakeFunctionCall(typeNameStr, tp.ListInstructions(expr), block, typeLineNo)
	return node
}
Example #3
0
func (p *Parser) variable(ns string) (node *tp.Instruction) {
	// ns = strings.Split(ns, ",")[0] // only use the first namespace -- can't efficiently search namespaces for global vars
	token := p.pop()
	lexeme, name, lineNo := token.Lexeme, token.Value, token.LineNumber
	sigil := "$"
	if lexeme == LVAR {
		sigil = "%"
	}
	var val *tp.Instruction
	var block []*tp.Instruction
	if p.peek().Lexeme == EQUAL {
		p.pop() // pop the equal sign
		switch p.peek().Lexeme {
		case STRING, REGEXP, POS, READ, ID, TYPE, GVAR, LVAR, LPAREN:
			val = p.expression()
		default:
			p.error("invalid expression in assignment to " + sigil + name)
		}
	}
	if p.peek().Lexeme == LBRACE {
		block = p.block()
	}
	if lexeme == LVAR {
		node = tp.MakeLocalVar(name, val, block, lineNo)
	} else {
		fullVarName := name
		// if the namespace is 'tritium', leave it off -- necessary to avoid breaking all that global capture stuff
		if ns != "tritium" {
			fullVarName = fmt.Sprintf("%s.%s", ns, name)
		}
		args := tp.ListInstructions(tp.MakeText(fullVarName, lineNo))
		if val != nil {
			args = append(args, val)
		}
		node = tp.MakeFunctionCall("var", args, block, lineNo)
	}
	return node
}
Example #4
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
}