Beispiel #1
0
func (p *Parser) Parse() *tp.ScriptObject {
	script := new(tp.ScriptObject)
	// script.Name = proto.String(p.FullPath)

	if !p.RootFile || TritiumParserShowRewriterFileName {
		script.Name = proto.String(filepath.Join(p.ScriptPath, p.FileName))
	} else {
		script.Name = proto.String("__rewriter__")
	}

	stmts := tp.ListInstructions()
	defs := make([]*tp.Function, 0) // Add a new constructor in instruction.go

	// Look for the namespace directive first.
	if p.peek().Lexeme == NAMESPACE {
		p.namespaces()
	}

	for p.peek().Lexeme != EOF {
		switch p.peek().Lexeme {
		case FUNC:
			defs = append(defs, p.definition())
		case OPEN:
			p.open(false)
		default:
			stmt := p.statement()
			stmts = append(stmts, stmt)
			// need to intersperse imports with definitions
			if constants.Instruction_InstructionType_name[int32(stmt.GetType())] == "IMPORT" {
				// Make a special function stub that represents the import.
				// Need to do this because we can't mix definitions and instructions in
				// the same array.
				imp := new(tp.Function)
				imp.Name = proto.String("@import")
				imp.Description = proto.String(stmt.GetValue())
				defs = append(defs, imp)
			}
		}
	}

	if len(defs) == 0 {
		defs = nil
	}

	var line int32
	if len(stmts) == 0 {
		stmts = nil
	} else {
		line = *stmts[0].LineNumber
	}

	script.Functions = defs
	script.Root = tp.MakeBlock(stmts, line)

	// if defs == nil && p.currentNamespace() != "tritium" {
	// 	panic(fmt.Sprintf("%s: %d -- custom modules may only be declared in function definition files", p.FileName, moduleLineNum))
	// }

	return script
}
Beispiel #2
0
func (p *Parser) definition() *tp.Function {
	isSignature := false
	node := new(tp.Function)
	// functions should be injected only into the first specified namespace
	node.Namespace = proto.String(p.Defspace)

	funcLineNo := p.pop().LineNumber // pop the `@func` keyword
	contextType := ""
	if p.peek().Lexeme == TYPE {
		contextType = p.pop().Value
		if p.peek().Lexeme != DOT {
			p.error("function context and function name must be separated by '.'")
		}
		p.pop() // pop the dot
	}

	if p.peek().Lexeme != ID {
		p.error("invalid function name in definition")
	}

	funcName := p.pop().Value
	funcFile := ""

	if len(p.ScriptPath) > 0 && p.ScriptPath != "." {
		funcFile = filepath.Join(p.ScriptPath, p.FileName)
	}

	if p.peek().Lexeme != LPAREN {
		p.error("parenthesized parameter list expected in function declaration")
	}
	p.pop() // pop the lparen
	params := p.parameters(funcName)
	if len(params) == 0 {
		params = nil
	}
	p.pop() // pop the rparen

	returnType := ""
	opensType := ""
	if p.peek().Lexeme == TYPE {
		isSignature = true
		returnType = p.pop().Value
		if p.peek().Lexeme == TYPE {
			opensType = p.pop().Value
		}
	}

	node.Name = proto.String(funcName)
	if len(funcFile) > 0 {
		node.Filename = proto.String(funcFile)
	}
	node.LineNumber = proto.Int32(funcLineNo)
	node.Args = params
	node.ScopeType = proto.String(contextType)
	node.ReturnType = proto.String(returnType)
	node.OpensType = proto.String(opensType)

	if isSignature {
		if p.peek().Lexeme == LBRACE {
			p.error("body not permitted in signature for built-in " + funcName)
		}
		node.BuiltIn = proto.Bool(true)
		return node
	}
	node.BuiltIn = proto.Bool(false)
	if p.peek().Lexeme != LBRACE {
		p.error("definition for " + funcName + " is missing a body")
	}
	funcBody := &tp.Instruction{
		Type: proto.Int32(constants.Instruction_BLOCK),
		// Children: p.block(),
		// use the wrapper to get a better error message
		Children: p.function_body(*node.Name),
	}
	node.Instruction = funcBody
	return node
}