// Compile takes a module identifier and a reader, and compiles its assembly source // code to an in-memory representation of agora bytecode, ready for execution. // If an error is encounted, it is returned as second value, otherwise it is nil. func (a *Asm) Compile(id string, r io.Reader) (*bytecode.File, error) { a.ended = false a.err = nil a.s = bufio.NewScanner(r) // Ignore everything before the [f] section a.findSection("[f]") // Edge case: if no func section (empty input), don't create the File, return if a.ended { return nil, ErrNoInput } a.f = bytecode.NewFile(id) // Read the first section, the other ones get called recursively as needed a.readFn() return a.f, a.err }
// Emit takes a module identifier, the symbols generated by the parser (the headless *AST*), // and the root scope, and emits the instructions required to execute the program. // It returns the in-memory bytecode representation of the program. If an error is // encountered, it is returned as second value, otherwise it returns nil. func (e *Emitter) Emit(id string, syms []*parser.Symbol, scps *parser.Scope) (*bytecode.File, error) { // Reset the internal fields e.err = nil e.kMap = make(map[*bytecode.Fn]map[kId]int) e.stackSz = make(map[*bytecode.Fn]int64) e.forNest = make(map[*bytecode.Fn][]*forData) // Create the bytecode representation structure f := bytecode.NewFile(id) fn := new(bytecode.Fn) fn.Header.Name = f.Name // Expected args and parent func are always 0 for top-level func // TODO : Line start and end f.Fns = append(f.Fns, fn) e.fnIx = []int64{0} e.emitBlock(f, fn, syms) return f, e.err }