go get github.com/pt-main/lcLc is a production-oriented toolkit for building things like language tools, compiler, interpreters or bytecode-driven processors in Go.
It is intentionally straightforward to adopt, while preserving industrial runtime properties:
- explicit execution lifecycle,
- deterministic output assembly,
- context-aware cancellation,
- thread-safe core primitives,
- clear extension contracts for parsers and command handlers, plugins.
Lc does not enforce one grammar style or one VM model.
Instead, it gives you one runtime surface with two engine backends:
- String Engine for text-first processing.
- Byte Engine for binary instruction execution.
Input string (code) and process that - edit, execute, generate code, etc.
Default lifecycle:
- store input in scope;
- parse input to
[]ParsedNode; - dispatch handlers by
ParsedNode.Switch; - emit output through
UEP.Generator(if need).
Input bytecode and process that.
Default lifecycle:
- store input in scope;
- parse input to
[]ParsedBytes; - decode opcode from
ParsedBytes.Switchbytes using configured endianness; - dispatch opcode handler;
- advance instruction pointer automatically or manually.
StringEngine Example
package main
import (
"fmt"
"strings"
"github.com/pt-main/lc"
enginepkg "github.com/pt-main/lc/engine"
"github.com/pt-main/lc/parsing/stringParsing"
)
func main() {
parser := &stringParsing.Parser2{}
engine, err := lc.NewEngineBuilder(lc.StringEngineType).
WithPipeline([]string{"main"}).
WithStringParser(parser).
WithDefaultEvents(true).
Build()
if err != nil {
panic(err)
}
err = engine.NewCommandString("print", func(se *enginepkg.StringEngine, node stringParsing.ParsedNode) error {
args, _ := node.Metadata["args"].(string)
return se.UEP.Generator.AddString(args, "main")
}, "append text to output")
if err != nil {
panic(err)
}
err = engine.ProcessString(strings.Join([]string{
"print service_start",
"print service_ready",
}, "\n"))
if err != nil {
panic(err)
}
out, err := engine.GetUEP().Generator.GetStringRes("\n")
if err != nil {
panic(err)
}
fmt.Println(out)
}ByteEngine Example
package main
import (
"fmt"
"github.com/pt-main/lc"
"github.com/pt-main/lc/parsing/byteParsing"
enginepkg "github.com/pt-main/lc/engine"
"github.com/pt-main/lc/tooling/bytecode"
)
func main() {
parser := &byteParsing.Parser1{
Config: byteParsing.Parser1Config{
GConfig: bytecode.GenerationConfig{
CommandBytelen: 1,
ArgscountBytelen: 1,
ArglenBytelen: 1,
Endianess: bytecode.LittleEndian,
},
Shifter: bytecode.Shift{},
},
}
engine, err := lc.NewEngineBuilder(lc.ByteEngineType).
WithPipeline([]string{"main"}).
WithByteParser(parser).
WithDefaultEvents(true).
Build()
if err != nil {
panic(err)
}
err = engine.NewCommandByte(1, func(be *enginepkg.ByteEngine, node byteParsing.ParsedBytes) error {
return be.UEP.Generator.AddBytes(node.Raw, "main")
}, "mirror instruction bytes", true)
if err != nil {
panic(err)
}
code := []byte{
0x01, 0x01, 0x03, 0x61, 0x62, 0x63, // opcode=1, args=1, argLen=3, arg="abc"
}
err = engine.ProcessBytes(code)
if err != nil {
panic(err)
}
out, err := engine.GetUEP().Generator.GetBytesRes()
if err != nil {
panic(err)
}
fmt.Printf("%x\n", out)
}For production embedding, typical builder configuration includes:
- explicit pipeline points (e.g.
bootstrap,main,finalize); - shared service context;
- structured logger instance;
- preloaded scope values (tenant/env/runtime metadata);
- custom events for audit/metrics/tracing.
Example:
engine, err := lc.NewEngineBuilder(lc.StringEngineType).
WithPipeline([]string{"bootstrap", "main", "finalize"}).
WithContext(ctx).
WithDefaultEvents(true).
WithLogger(logger).
WithScope(scope).
WithStringParser(parser).
Build()Parser1:- regex grammar matching,
- named capture-group metadata,
- line continuation support,
- bracket-balance support.
Parser2: compact line-orientedcommand argsparser.Parser3/package: Ast peg-like parser works with Lexer.Lexer: ordered regexp2 tokenizer with prev/next node links and bracket balance.
Parser1: binary parser with configurable field lengths and endianness.ParsedBytesmodel withSwitch,Args,Raw, andMetadata.
ProcessString(input string) errorProcessStringWithCtx(input string, ctx context.Context) errorProcessBytes(input []byte) errorProcessBytesWithCtx(input []byte, ctx context.Context) error
NewCommandString(cmdSwitch string, handler ..., doc string) errorNewCommandByte(opcode int, handler ..., name string, autoBytecodeIdxShift bool) error
AddToBytecodeIdx(n int)SetBytecodeIdx(n int)GetBytecodeIdx() (*int, error)
- Event handlers run in registration order.
- Generator result follows declared pipeline order.
Process[*]WithCtxrespects cancellation/deadline.- Default String dispatch skips unknown commands.
- Default Byte dispatch expects valid opcode/autoshift registration for processed commands.
String keys:
INPUT stringPARSED []ParsedNode
Byte keys:
INPUT []bytePARSED []ParsedBytesENDIANESS intBYECODE_IDX *int
Treat these names as reserved runtime contract keys.
Other keys you and names you can find in public//
Lc provides core mechanisms for operational visibility:
- thread-safe
core.Logger, - event lifecycle hooks (call start/call end),
- centralized runtime scope for contextual metadata,
- structured error wrapping in default event flows.
Apache 2.0 - see LICENSE.
By Pt.
