compiler

package
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 20, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// DefaultSourceFileExt is the default extension used to resolve file imports.
	DefaultSourceFileExt = ".kvn"

	// AssignmentModeSmart declares a variable in current scope for unresolved '=' assignments.
	AssignmentModeSmart = AssignmentMode(0)

	// AssignmentModeStrict requires variables to already exist for '=' assignments.
	AssignmentModeStrict = AssignmentMode(1)
)

Variables

This section is empty.

Functions

func ComputeMaxStack

func ComputeMaxStack(instructions bc.Instructions) int

ComputeMaxStack returns the maximum operand-stack depth that the given bytecode instruction stream can reach during execution.

func NewAbortCheck added in v0.5.1

func NewAbortCheck() bc.Instruction

func NewAccessIndex added in v0.5.1

func NewAccessIndex() bc.Instruction

func NewAccessSelector added in v0.5.1

func NewAccessSelector() bc.Instruction

func NewAndJump added in v0.5.1

func NewAndJump(target int) bc.Instruction

func NewBinaryOp added in v0.5.1

func NewBinaryOp(tokenID token.Token) bc.Instruction

func NewCallFunction added in v0.5.1

func NewCallFunction(numArgs int, isSpread bool) bc.Instruction

func NewCallMethod added in v0.5.1

func NewCallMethod(methodIndex int, numArgs int, isSpread bool) bc.Instruction

func NewContains added in v0.5.1

func NewContains() bc.Instruction

func NewDefer added in v0.5.1

func NewDefer(numArgs int) bc.Instruction

func NewDeferMethod added in v0.5.1

func NewDeferMethod(methodIndex int, numArgs int) bc.Instruction

func NewDefineLocal added in v0.5.1

func NewDefineLocal(localIndex int) bc.Instruction

func NewEqual added in v0.5.1

func NewEqual() bc.Instruction

func NewFormatRuntimeSpec added in v0.5.1

func NewFormatRuntimeSpec() bc.Instruction

func NewFormatStaticSpec added in v0.5.1

func NewFormatStaticSpec(formatSpecStaticIndex int) bc.Instruction

func NewImmutable added in v0.5.1

func NewImmutable() bc.Instruction

func NewImportBuiltinModule added in v0.5.1

func NewImportBuiltinModule(moduleStaticID int) bc.Instruction

func NewIterInit added in v0.5.1

func NewIterInit() bc.Instruction

func NewIterKey added in v0.5.1

func NewIterKey() bc.Instruction

func NewIterNext added in v0.5.1

func NewIterNext() bc.Instruction

func NewIterValue added in v0.5.1

func NewIterValue() bc.Instruction

func NewJump added in v0.5.1

func NewJump(target int) bc.Instruction

func NewJumpFalsy added in v0.5.1

func NewJumpFalsy(target int) bc.Instruction

func NewLoadBuiltinFunction added in v0.5.1

func NewLoadBuiltinFunction(builtinFuncID int) bc.Instruction

func NewLoadFree added in v0.5.1

func NewLoadFree(freeIndex int) bc.Instruction

func NewLoadFreePtr added in v0.5.1

func NewLoadFreePtr(freeIndex int) bc.Instruction

func NewLoadGlobal added in v0.5.1

func NewLoadGlobal(globalIndex int) bc.Instruction

func NewLoadLocal added in v0.5.1

func NewLoadLocal(localIndex int) bc.Instruction

func NewLoadLocalPtr added in v0.5.1

func NewLoadLocalPtr(localIndex int) bc.Instruction

func NewLoadStaticBytes added in v0.5.1

func NewLoadStaticBytes(i int) bc.Instruction

func NewLoadStaticCompiledFunction added in v0.5.1

func NewLoadStaticCompiledFunction(i int) bc.Instruction

func NewLoadStaticDecimal added in v0.5.1

func NewLoadStaticDecimal(i int) bc.Instruction

func NewLoadStaticFormatSpec added in v0.5.1

func NewLoadStaticFormatSpec(i int) bc.Instruction

func NewLoadStaticPrimitive added in v0.5.1

func NewLoadStaticPrimitive(i int) bc.Instruction

func NewLoadStaticRunes added in v0.5.1

func NewLoadStaticRunes(i int) bc.Instruction

func NewLoadStaticString added in v0.5.1

func NewLoadStaticString(i int) bc.Instruction

func NewLoadStaticTime added in v0.5.1

func NewLoadStaticTime(i int) bc.Instruction

func NewMakeArray added in v0.5.1

func NewMakeArray(numElements int) bc.Instruction

func NewMakeClosure added in v0.5.1

func NewMakeClosure(staticFuncIndex int, numFreeVars int) bc.Instruction

func NewMakeRecord added in v0.5.1

func NewMakeRecord(numFields int) bc.Instruction

func NewNotEqual added in v0.5.1

func NewNotEqual() bc.Instruction

func NewOrJump added in v0.5.1

func NewOrJump(target int) bc.Instruction

func NewPop added in v0.5.1

func NewPop() bc.Instruction

func NewPushBool added in v0.5.1

func NewPushBool(b bool) bc.Instruction

func NewPushByte added in v0.5.1

func NewPushByte(i byte) bc.Instruction

func NewPushInt added in v0.5.1

func NewPushInt(i int32) bc.Instruction

func NewPushRune added in v0.5.1

func NewPushRune(i rune) bc.Instruction

func NewPushUndefined added in v0.5.1

func NewPushUndefined() bc.Instruction

func NewReturn added in v0.5.1

func NewReturn(hasResult bool) bc.Instruction

func NewSlice added in v0.5.1

func NewSlice() bc.Instruction

func NewSliceStep added in v0.5.1

func NewSliceStep() bc.Instruction

func NewStoreFree added in v0.5.1

func NewStoreFree(freeIndex int) bc.Instruction

func NewStoreGlobal added in v0.5.1

func NewStoreGlobal(globalIndex int) bc.Instruction

func NewStoreIndexedFree added in v0.5.1

func NewStoreIndexedFree(freeIndex int, numSelectors int) bc.Instruction

func NewStoreIndexedGlobal added in v0.5.1

func NewStoreIndexedGlobal(globalIndex int, numSelectors int) bc.Instruction

func NewStoreIndexedLocal added in v0.5.1

func NewStoreIndexedLocal(localIndex int, numSelectors int) bc.Instruction

func NewStoreLocal added in v0.5.1

func NewStoreLocal(localIndex int) bc.Instruction

func NewSuspend added in v0.5.1

func NewSuspend() bc.Instruction

func NewUnaryBitNot added in v0.5.1

func NewUnaryBitNot() bc.Instruction

func NewUnaryNeg added in v0.5.1

func NewUnaryNeg() bc.Instruction

func NewUnaryNot added in v0.5.1

func NewUnaryNot() bc.Instruction

Types

type AssignmentMode

type AssignmentMode int

AssignmentMode controls how plain '=' handles unresolved identifiers.

type Compiler

type Compiler struct {
	// contains filtered or unexported fields
}

Compiler compiles the AST into a bytecode.

func NewCompiler added in v0.4.1

func NewCompiler(
	oc *OptimizationConfig,
	sb *StaticBuilder,
	file *ast.SourceFile,
	symbolTable *SymbolTable,
	allowedModules []string,
	customModules map[string][]byte,
	trace io.Writer,
) *Compiler

New creates a Compiler.

func (*Compiler) Bytecode

func (c *Compiler) Bytecode() *vm.Bytecode

Bytecode returns a compiled bytecode.

func (*Compiler) Compile

func (c *Compiler) Compile(file *ast.SourceFile, src []byte, trace io.Writer) error

Compile compiles the source file into an optimized bytecode.

func (*Compiler) CompileNode added in v0.6.1

func (c *Compiler) CompileNode(node ast.Node) (err error)

Compile compiles the AST node.

func (*Compiler) EnableFileImport

func (c *Compiler) EnableFileImport(enable bool)

EnableFileImport enables or disables module loading from local files. Local file modules are disabled by default.

func (*Compiler) GetAssignmentMode

func (c *Compiler) GetAssignmentMode() AssignmentMode

GetAssignmentMode returns the active assignment mode.

func (*Compiler) GetImportFileExt

func (c *Compiler) GetImportFileExt() []string

GetImportFileExt returns the current list of extension name. These are the complementary suffix of the source file to search and load local module files.

func (*Compiler) Optimize added in v0.6.1

func (c *Compiler) Optimize(node ast.Node) (ast.Node, error)

Optimize runs the AST optimization pipeline, re-iterating until no changes occur or MaxPasses is reached.

func (*Compiler) SetAssignmentMode

func (c *Compiler) SetAssignmentMode(mode AssignmentMode)

SetAssignmentMode sets how plain '=' handles unresolved identifiers.

func (*Compiler) SetImportDir

func (c *Compiler) SetImportDir(dir string)

SetImportDir sets the initial import directory path for file imports.

func (*Compiler) SetImportFileExt

func (c *Compiler) SetImportFileExt(exts ...string) error

SetImportFileExt sets the extension name of the source file for loading local module files. Use this method if you want other source file extension than ".kvn". This function requires at least one argument, since it will replace the current list of extension name.

type CompilerError

type CompilerError struct {
	FileSet *ast.SourceFileSet
	Node    ast.Node
	Err     error
}

CompilerError represents a compiler error.

func (*CompilerError) Error

func (e *CompilerError) Error() string

type OptimizationConfig added in v0.6.1

type OptimizationConfig struct {
	MaxPasses int
	OnPass    func(name string, changed bool)

	// Unified constant folding via speculative compile+run of candidate subtrees in a real VM (O3 only — see design
	// notes above on why this one pass is gated separately from the rest of O1/O2). Subsumes what would otherwise be
	// split into FoldConstantExpressions, FoldConstantBuiltinCalls, FoldConstantIndexing, FoldConstantFString, and
	// FoldStringConcatChains. Admits MethodCall/Call in addition to everything FoldConstantArithmetic admits — see
	// isFoldableExpr.
	FoldConstantSubexpressions bool

	// The cost-bounded tier of constant folding (O1+): the same speculative compile+run mechanism as
	// FoldConstantSubexpressions, restricted to subtrees of scalar literals combined via Unary/Binary operators
	// only (arithmetic, comparison, equality, logical — see isFoldableArithmeticExpr). No MethodCall/Call, so no
	// possibility of an expensive (if pure) method/builtin body running during evaluation.
	FoldConstantArithmetic bool

	// Structural/logical simplifications that don't require full evaluation of operands (O1).
	FoldLogicalShortCircuit bool

	// Propagation of values and copies into use sites (O1-O2).
	PropagateConstants bool
	CopyPropagation    bool

	// Dead code and branch simplification (O2).
	SimplifyConstantConditions          bool
	EliminateDeadBranches               bool
	EliminateNoOpIfStatements           bool
	EliminateUnreachableAfterTerminator bool
	EliminateDeadAssignments            bool
}

OptimizationConfig controls which AST optimization passes are enabled and how many times the optimization loop runs. Each pass is independently gated by a boolean flag. MaxPasses caps the number of full optimization cycles; the loop exits early once a full cycle produces no changes.

Design notes:

  • Passes are grouped by cost/risk. O0 disables everything; O1 runs cheap value-preserving rewrites plus the cost-bounded arithmetic/logical tier of constant folding (FoldConstantArithmetic — see below); O2 adds dead-code and branch simplification; O3 adds the general, unbounded-cost tier (FoldConstantSubexpressions — see below) and raises MaxPasses for deeper convergence (interprocedural analysis — pure-function folding, small-function inlining — is not yet implemented).
  • FoldConstantSubexpressions and FoldConstantArithmetic both work by speculatively compiling+running the candidate subtree via evalConstantExpr — there is no separate hand-rolled evaluator for either tier, so both stay byte-identical to runtime behavior automatically as new types/operators/methods are added. They differ only in eligibility: isFoldableArithmeticExpr (FoldConstantArithmetic, O1+) admits solely scalar literals combined via Unary/Binary operators — arithmetic, comparison, equality, and logical, since the AST has one node kind per operator arity rather than one per token, so no operator needs special-casing. That bounds the candidate subtree's compiled size and execution cost to be proportional to the AST alone. isFoldableExpr (FoldConstantSubexpressions, O3 only) additionally admits MethodCall/Call, which may be pure yet arbitrarily expensive (e.g. a large repeat/sort/string op) — see docs/purity.md and OPTIMIZER_REVIEW.md finding #2 for the compile-time-cost/DoS angle this creates for code that turns out to be provably dead. O1/O2 exist as cheaper tiers precisely so a caller who wants ordinary dead-code/branch simplification (plus bounded-cost arithmetic folding) without paying for open-ended speculative VM execution has that option.
  • passes() runs FoldConstantArithmetic FIRST within a cycle and FoldConstantSubexpressions LAST, specifically so every pass that can shrink or eliminate code (dead branches, unreachable-after-terminator, dead assignments, plus the cheap FoldLogicalShortCircuit / propagation passes) gets first crack at reducing what's left to fold with the general pass, while itself running early enough that its own results (e.g. `(1+2) && x` collapsing its LHS to `3`) are visible to FoldLogicalShortCircuit and the other passes in the same cycle. A condition that's already a literal in source (`if false { expensive() }`) or code after a literal terminator doesn't need any folding to be recognized as dead, so ordering the expensive pass last means such code never reaches it in the same cycle it's eliminated in. This doesn't help when a condition only *becomes* constant as a result of folding (that still needs an extra cycle to converge — MaxPasses accounts for this), but it directly protects the common case of already-dead code from paying for open-ended speculative evaluation at all. Note this ordering creates no duplicate work between the two folding passes: by the time FoldConstantSubexpressions runs, anything FoldConstantArithmetic already folded is a literal, which its own rewriteExpr skips immediately via IsScalarLiteral().
  • The unified constant-folding passes subsume several patterns that would otherwise be implemented as separate detectors (arithmetic, string concat, builtin calls with literal args, indexing on literals, f-string collapse, ...). They work by speculatively compiling+running eligible subtrees, which keeps the optimizer in sync with the runtime automatically as new types/operators/methods are added.
  • OnPass, if set, is invoked after each pass with (pass name, changed?). Useful for tracing/regression debugging when implementing pass bodies.

func O0 added in v0.6.1

func O0() *OptimizationConfig

func O1 added in v0.6.1

func O1() *OptimizationConfig

func O2 added in v0.6.1

func O2() *OptimizationConfig

func O3 added in v0.6.1

func O3() *OptimizationConfig

func (*OptimizationConfig) SetO0 added in v0.6.1

func (oc *OptimizationConfig) SetO0()

SetO0 disables all optimizations; no passes run.

func (*OptimizationConfig) SetO1 added in v0.6.1

func (oc *OptimizationConfig) SetO1()

SetO1 enables cheap structural/logical simplifications, constant propagation, and the cost-bounded arithmetic tier of constant folding (FoldConstantArithmetic). Every O1 pass either only reads an already-literal AST node, or (for FoldConstantArithmetic) is restricted by isFoldableArithmeticExpr to subtrees whose evaluation cost is proportional to AST size alone — no pass here can trigger open-ended work the way a MethodCall/Call fold could. MaxPasses = 2 so that propagation→propagation-enabled-rewrites can converge in a single Optimize invocation.

func (*OptimizationConfig) SetO2 added in v0.6.1

func (oc *OptimizationConfig) SetO2()

SetO2 adds copy propagation and dead-code/branch simplification on top of O1. No additional speculative evaluation beyond what O1's FoldConstantArithmetic already does — every new O2 pass either substitutes already-known literals or removes structurally-provable dead code. MaxPasses = 3 for deeper convergence.

func (*OptimizationConfig) SetO3 added in v0.6.1

func (oc *OptimizationConfig) SetO3()

SetO3 adds FoldConstantSubexpressions — the general tier of constant folding, which (unlike O1's FoldConstantArithmetic) also admits MethodCall/Call and therefore isn't bounded by AST size alone (see the design notes on OptimizationConfig). Deliberately gated to O3 only, not O1/O2, so a caller can get all of O2's dead-code/branch simplification and bounded-cost arithmetic folding without paying for open-ended speculative VM execution. Also raises MaxPasses to 10 (from O2's 3) for deeper convergence. Interprocedural analysis (pure-function folding, small-function inlining) across user-defined functions is not yet implemented.

type StaticBuilder added in v0.4.1

type StaticBuilder struct {
	// contains filtered or unexported fields
}

func NewStaticBuilder added in v0.4.1

func NewStaticBuilder() *StaticBuilder

func (*StaticBuilder) AddBytes added in v0.5.1

func (b *StaticBuilder) AddBytes(v core.Bytes) int

func (*StaticBuilder) AddCompiledFunction added in v0.4.1

func (b *StaticBuilder) AddCompiledFunction(v core.CompiledFunction) int

func (*StaticBuilder) AddDecimal added in v0.4.1

func (b *StaticBuilder) AddDecimal(v dec128.Dec128) int

func (*StaticBuilder) AddFormatSpec added in v0.4.1

func (b *StaticBuilder) AddFormatSpec(v core.FormatSpec) int

func (*StaticBuilder) AddPrimitive added in v0.4.1

func (b *StaticBuilder) AddPrimitive(v core.Value) int

func (*StaticBuilder) AddRunes added in v0.4.1

func (b *StaticBuilder) AddRunes(v core.Runes) int

func (*StaticBuilder) AddString added in v0.4.1

func (b *StaticBuilder) AddString(v string) int

func (*StaticBuilder) AddTime added in v0.5.1

func (b *StaticBuilder) AddTime(v time.Time) int

func (*StaticBuilder) Build added in v0.4.1

func (b *StaticBuilder) Build() core.Static

type Symbol added in v0.4.1

type Symbol struct {
	Name          string
	Scope         SymbolScope
	Index         int
	LocalAssigned bool // if the local symbol is assigned at least once
}

Symbol represents a symbol in the symbol table.

type SymbolScope added in v0.4.1

type SymbolScope string

SymbolScope represents a symbol scope.

const (
	ScopeGlobal  SymbolScope = "GLOBAL"
	ScopeLocal   SymbolScope = "LOCAL"
	ScopeBuiltin SymbolScope = "BUILTIN"
	ScopeFree    SymbolScope = "FREE"
)

List of symbol scopes

type SymbolTable added in v0.4.1

type SymbolTable struct {
	// contains filtered or unexported fields
}

SymbolTable represents a symbol table.

func NewSymbolTable added in v0.4.1

func NewSymbolTable() *SymbolTable

NewSymbolTable creates a SymbolTable.

func (*SymbolTable) BuiltinSymbols added in v0.4.1

func (t *SymbolTable) BuiltinSymbols() []*Symbol

BuiltinSymbols returns builtin symbols for the scope.

func (*SymbolTable) Define added in v0.4.1

func (t *SymbolTable) Define(name string) *Symbol

Define adds a new symbol in the current scope.

func (*SymbolTable) DefineBuiltin added in v0.4.1

func (t *SymbolTable) DefineBuiltin(index int, name string) *Symbol

DefineBuiltin adds a symbol for builtin function.

func (*SymbolTable) Fork added in v0.4.1

func (t *SymbolTable) Fork(block bool) *SymbolTable

Fork creates a new symbol table for a new scope.

func (*SymbolTable) FreeSymbols added in v0.4.1

func (t *SymbolTable) FreeSymbols() []*Symbol

FreeSymbols returns free symbols for the scope.

func (*SymbolTable) MaxSymbols added in v0.4.1

func (t *SymbolTable) MaxSymbols() int

MaxSymbols returns the total number of symbols defined in the scope.

func (*SymbolTable) Names added in v0.4.1

func (t *SymbolTable) Names() []string

Names returns the name of all the symbols.

func (*SymbolTable) Parent added in v0.4.1

func (t *SymbolTable) Parent(skipBlock bool) *SymbolTable

Parent returns the outer scope of the current symbol table.

func (*SymbolTable) Resolve added in v0.4.1

func (t *SymbolTable) Resolve(
	name string,
	recur bool,
) (*Symbol, int, bool)

Resolve resolves a symbol with a given name.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL