mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 18:37:26 +08:00
220 lines
5.3 KiB
Go
220 lines
5.3 KiB
Go
//
|
|
// ast.go
|
|
//
|
|
// Copyright (c) 2019-2024 Markku Rossi
|
|
//
|
|
// All rights reserved.
|
|
//
|
|
|
|
package ast
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
|
|
"source.quilibrium.com/quilibrium/monorepo/bedlam/compiler/ssa"
|
|
"source.quilibrium.com/quilibrium/monorepo/bedlam/compiler/utils"
|
|
"source.quilibrium.com/quilibrium/monorepo/bedlam/types"
|
|
)
|
|
|
|
// Codegen implements compilation stack.
|
|
type Codegen struct {
|
|
logger *utils.Logger
|
|
Params *utils.Params
|
|
Verbose bool
|
|
Package *Package
|
|
Packages map[string]*Package
|
|
MainInputSizes [][]int
|
|
Stack []Compilation
|
|
Types map[types.ID]*TypeInfo
|
|
Native map[string]*circuit.Circuit
|
|
HeapID int
|
|
}
|
|
|
|
// NewCodegen creates a new compilation.
|
|
func NewCodegen(logger *utils.Logger, pkg *Package,
|
|
packages map[string]*Package, params *utils.Params,
|
|
mainInputSizes [][]int) *Codegen {
|
|
|
|
return &Codegen{
|
|
logger: logger,
|
|
Params: params,
|
|
Verbose: params.Verbose,
|
|
Package: pkg,
|
|
Packages: packages,
|
|
MainInputSizes: mainInputSizes,
|
|
Types: make(map[types.ID]*TypeInfo),
|
|
Native: make(map[string]*circuit.Circuit),
|
|
}
|
|
}
|
|
|
|
func (ctx *Codegen) errorLoc(err error) error {
|
|
if !ctx.Params.QCLCErrorLoc {
|
|
return err
|
|
}
|
|
|
|
for skip := 2; ; skip++ {
|
|
pc, file, line, ok := runtime.Caller(skip)
|
|
if !ok {
|
|
return err
|
|
}
|
|
f := runtime.FuncForPC(pc)
|
|
if f != nil && strings.HasSuffix(f.Name(), ".errf") {
|
|
continue
|
|
}
|
|
fmt.Printf("%s:%d: MCPLC error:\n\u2514\u2574%s\n", file, line, err)
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Error logs an error message.
|
|
func (ctx *Codegen) Error(locator utils.Locator, msg string) error {
|
|
return ctx.errorLoc(ctx.logger.Errorf(locator.Location(), "%s", msg))
|
|
}
|
|
|
|
// Errorf logs an error message.
|
|
func (ctx *Codegen) Errorf(locator utils.Locator, format string,
|
|
a ...interface{}) error {
|
|
return ctx.errorLoc(ctx.logger.Errorf(locator.Location(), format, a...))
|
|
}
|
|
|
|
// Warningf logs a warning message
|
|
func (ctx *Codegen) Warningf(locator utils.Locator, format string,
|
|
a ...interface{}) {
|
|
ctx.logger.Warningf(locator.Location(), format, a...)
|
|
}
|
|
|
|
// DefineType defines the argument type and assigns it an unique type
|
|
// ID.
|
|
func (ctx *Codegen) DefineType(t *TypeInfo) types.ID {
|
|
id := types.ID(len(ctx.Types) + 0x80000000)
|
|
ctx.Types[id] = t
|
|
return id
|
|
}
|
|
|
|
// LookupFunc resolves the named function from the context.
|
|
func (ctx *Codegen) LookupFunc(block *ssa.Block, ref *VariableRef) (
|
|
*Func, error) {
|
|
|
|
// First, check method calls.
|
|
if len(ref.Name.Package) > 0 {
|
|
// Check if package name is bound to a value.
|
|
var b ssa.Binding
|
|
var ok bool
|
|
|
|
b, ok = block.Bindings.Get(ref.Name.Package)
|
|
if !ok {
|
|
// Check names in the current package.
|
|
b, ok = ctx.Package.Bindings.Get(ref.Name.Package)
|
|
}
|
|
if ok {
|
|
var typeInfo types.Info
|
|
if b.Type.Type == types.TPtr {
|
|
typeInfo = *b.Type.ElementType
|
|
} else {
|
|
typeInfo = b.Type
|
|
}
|
|
|
|
info, ok := ctx.Types[typeInfo.ID]
|
|
if !ok {
|
|
return nil, ctx.Errorf(ref, "%s undefined", ref)
|
|
}
|
|
method, ok := info.Methods[ref.Name.Name]
|
|
if !ok {
|
|
return nil, ctx.Errorf(ref, "%s undefined", ref)
|
|
}
|
|
return method, nil
|
|
}
|
|
}
|
|
|
|
// Next, check function calls.
|
|
var pkgName string
|
|
if len(ref.Name.Package) > 0 {
|
|
pkgName = ref.Name.Package
|
|
} else {
|
|
pkgName = ref.Name.Defined
|
|
}
|
|
pkg, ok := ctx.Packages[pkgName]
|
|
if !ok {
|
|
return nil, ctx.Errorf(ref, "package '%s' not found", pkgName)
|
|
}
|
|
called, ok := pkg.Functions[ref.Name.Name]
|
|
if !ok {
|
|
return nil, nil
|
|
}
|
|
return called, nil
|
|
}
|
|
|
|
// Func returns the current function in the current compilation.
|
|
func (ctx *Codegen) Func() *Func {
|
|
if len(ctx.Stack) == 0 {
|
|
return nil
|
|
}
|
|
return ctx.Stack[len(ctx.Stack)-1].Called
|
|
}
|
|
|
|
// Scope returns the value scope in the current compilation.
|
|
func (ctx *Codegen) Scope() ssa.Scope {
|
|
if ctx.Func() != nil {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// PushCompilation pushes a new compilation to the compilation stack.
|
|
func (ctx *Codegen) PushCompilation(start, ret, caller *ssa.Block,
|
|
called *Func) {
|
|
|
|
ctx.Stack = append(ctx.Stack, Compilation{
|
|
Start: start,
|
|
Return: ret,
|
|
Caller: caller,
|
|
Called: called,
|
|
})
|
|
}
|
|
|
|
// PopCompilation pops the topmost compilation from the compilation
|
|
// stack.
|
|
func (ctx *Codegen) PopCompilation() {
|
|
if len(ctx.Stack) == 0 {
|
|
panic("compilation stack underflow")
|
|
}
|
|
ctx.Stack = ctx.Stack[:len(ctx.Stack)-1]
|
|
}
|
|
|
|
// Start returns the start block of the current compilation.
|
|
func (ctx *Codegen) Start() *ssa.Block {
|
|
return ctx.Stack[len(ctx.Stack)-1].Start
|
|
}
|
|
|
|
// Return returns the return block of the current compilation.
|
|
func (ctx *Codegen) Return() *ssa.Block {
|
|
return ctx.Stack[len(ctx.Stack)-1].Return
|
|
}
|
|
|
|
// Caller returns the caller block of the current compilation.
|
|
func (ctx *Codegen) Caller() *ssa.Block {
|
|
return ctx.Stack[len(ctx.Stack)-1].Caller
|
|
}
|
|
|
|
// HeapVar returns the name of the next global heap variable.
|
|
func (ctx *Codegen) HeapVar() string {
|
|
name := fmt.Sprintf("$heap%v", ctx.HeapID)
|
|
ctx.HeapID++
|
|
return name
|
|
}
|
|
|
|
// Compilation contains information about a compilation
|
|
// scope. Toplevel, each function call, and each nested block specify
|
|
// their own scope with their own variable bindings.
|
|
type Compilation struct {
|
|
Start *ssa.Block
|
|
Return *ssa.Block
|
|
Caller *ssa.Block
|
|
Called *Func
|
|
// XXX Bindings
|
|
// XXX Parent scope.
|
|
}
|