Example #1
0
// 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
}
Example #2
0
// 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
}