lc

package module
v1.3.2 Latest Latest
Warning

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

Go to latest
Published: Jun 22, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

README

Lc - "Language creator" and language and dsl devkit

banner-low

Go Reference Go Report Card Release

go get github.com/pt-main/lc

Lc is a production-oriented toolkit for building language runtimes, compiler-like execution pipelines, command interpreters, and 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.

Engine model

String Engine

Best for command languages, script-like syntaxes, config runtimes, and text transformation flows.

Default lifecycle:

  1. store input in scope;
  2. parse input to []ParsedNode;
  3. dispatch handlers by ParsedNode.Switch;
  4. emit output through UEP.Generator (if need).
Byte Engine

Best for opcode streams, compact protocol runtimes, and binary execution loops.

Default lifecycle:

  1. store input in scope (INPUT []byte);
  2. parse input to []ParsedBytes;
  3. decode opcode from ParsedBytes.Switch bytes using configured endianness;
  4. dispatch opcode handler;
  5. advance instruction pointer automatically or manually.

Quick start - String Engine

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)
}

Quick start - Byte Engine

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)
}

Industrial setup pattern

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()

Built-in parser modules

stringParsing
  • Parser1:
    • regex grammar matching,
    • named capture-group metadata,
    • line continuation support,
    • bracket-balance support.
  • Parser2: compact line-oriented command args parser.
  • Lexer: ordered regexp2 tokenizer with __prev / __next node links.
byteParsing
  • Parser1: binary parser with configurable field lengths and endianness.
  • ParsedBytes model with Switch, Args, Raw, and Metadata.

Public runtime API overview

Processing
  • ProcessString(input string) error
  • ProcessStringWithCtx(input string, ctx context.Context) error
  • ProcessBytes(input []byte) error
  • ProcessBytesWithCtx(input []byte, ctx context.Context) error
Command registration
  • NewCommandString(cmdSwitch string, handler ..., doc string) error
  • NewCommandByte(opcode int, handler ..., name string, autoBytecodeIdxShift bool) error
Byte instruction pointer controls
  • AddToBytecodeIdx(n int)
  • SetBytecodeIdx(n int)
  • GetBytecodeIdx() (*int, error)

Execution semantics

  • Event handlers run in registration order.
  • Generator result follows declared pipeline order.
  • Process*WithCtx respects cancellation/deadline.
  • Default String dispatch skips unknown commands.
  • Default Byte dispatch expects valid opcode/autoshift registration for processed commands.

Reserved scope keys used by default events

String keys:

  • INPUT string
  • PARSED []ParsedNode

Byte keys:

  • INPUT []byte
  • PARSED []ParsedBytes
  • ENDIANESS int
  • BYECODE_IDX *int

Treat these names as reserved runtime contract keys.

Observability

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.

Repository structure

  • builder.go - fluent builder.
  • engine.go - universal runtime wrapper and command registration.
  • main.go - public constructors for String/Byte engines.
  • engine/ - concrete engine implementations.
  • engine/core/ - generator, events, logger, shared params.
  • engine/events/ - default parse/call handlers.
  • public/ - public constants or types (event names, scope keys, etc.)
  • parsing/ - basic parsing.
  • parsing/stringParsing/ - text parser ecosystem.
  • parsing/stringParsing/parser3/ - ast parser with peg-like logics.
  • parsing/byteParsing/ - byte parser ecosystem.
  • tooling/bytecode/ - byte conversion, shift helpers and instructions generation.
  • tooling/plugins/ - plugins core.
  • example/ - example languages and other examples.
  • backup/ - five2 backup files.

License

Apache 2.0 - see LICENSE.

By Pt.

Documentation

Index

Constants

View Source
const Version = "1.3.2"

Variables

This section is empty.

Functions

func NewByteEngine

func NewByteEngine(
	generator_res_type public.ResType,
	pipeline []string,
	add_default_events bool,
	parser byteParser,
	endianess public.EndianType,
	colorEnable bool,
	context context.Context,
) *engine.ByteEngine

NewByteEngine creates a byte-oriented engine for binary formats or bytecode.

The endianess parameter (e.g., bytecode.LittleEndian) is stored in scope.

It registers default events when add_default_events is true.

The parser must implement paraing.ParserInterface.

func NewStringEngine

func NewStringEngine(
	generator_res_type public.ResType,
	pipeline []string,
	add_default_events bool,
	parser stringParser,
	colorEnable bool,
	context context.Context,
) *engine.StringEngine

NewStringEngine creates a ready-to-use string-based engine. Parameters:

generator_res_type – core.StringResType (usually) for text generation.
pipeline – ordered list of generation points (e.g., []string{"pre","main"}).
add_default_events – if true, registers standard parsing and call events.
parser – an implementation parser.ParserInterface.

Returns a StringEngine with empty command map and initialized UEP.

Types

type EngineBuilder

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

EngineBuilder is a fluent builder for constructing universal engines. It allows to configure pipeline stages, event handling, logging, custom parsers, scope variables, and byte order before calling Build(). Use NewEngineBuilder to create a builder instance.

func NewEngineBuilder

func NewEngineBuilder(engineType public.EngineType, resType public.ResType) *EngineBuilder

NewEngineBuilder creates a new EngineBuilder for the given engine type. engineType must be either ByteEngineType or StringEngineType. Defaults: pipeline = []string{"main"}, default events enabled, endianess = bytecode.LittleEndian, empty scope. Example:

builder := lc.NewEngineBuilder(lc.StringEngineType).
            WithPipeline([]string{"pre","main"}).
            WithStringParser(myParser)

func (*EngineBuilder) Build

func (b *EngineBuilder) Build() (*EngineUniversal, error)

Build constructs and returns an EngineUniversal or an error if required components are missing (e.g., a string parser for a StringEngine). The returned engineUniversal can process strings or bytes depending on its type and provides methods to register commands.

func (*EngineBuilder) WithByteParser

func (b *EngineBuilder) WithByteParser(parser byteParser) *EngineBuilder

func (*EngineBuilder) WithColors

func (b *EngineBuilder) WithColors() *EngineBuilder

func (*EngineBuilder) WithContext

func (b *EngineBuilder) WithContext(context context.Context) *EngineBuilder

func (*EngineBuilder) WithDefaultEvents

func (b *EngineBuilder) WithDefaultEvents(add bool) *EngineBuilder

func (*EngineBuilder) WithEndianess

func (b *EngineBuilder) WithEndianess(endianess public.EndianType) *EngineBuilder

func (*EngineBuilder) WithLogger

func (b *EngineBuilder) WithLogger(logger *core.Logger) *EngineBuilder

func (*EngineBuilder) WithPipeline

func (b *EngineBuilder) WithPipeline(pipeline []string) *EngineBuilder

func (*EngineBuilder) WithPlugins added in v1.3.2

func (b *EngineBuilder) WithPlugins(plugins ...plugin.PluginInterface) *EngineBuilder

func (*EngineBuilder) WithScope

func (b *EngineBuilder) WithScope(scope core.ScopeType) *EngineBuilder

func (*EngineBuilder) WithStringParser

func (b *EngineBuilder) WithStringParser(parser stringParser) *EngineBuilder

type EngineUniversal

type EngineUniversal struct {
	Plugins      *lcplugin.PluginManager
	Type         public.EngineType
	StringEngine *engine.StringEngine
	ByteEngine   *engine.ByteEngine

	Context context.Context
	// contains filtered or unexported fields
}

func (*EngineUniversal) GetUEP

func (*EngineUniversal) NewCommandByte

func (e *EngineUniversal) NewCommandByte(
	opcode int, handler core.CommandType[engine.ByteEngine, byteParsing.ParsedBytes], name string,
	autoByecodeIdxShift bool,
) error

NewCommandByte registers a bytecode command identified by an opcode. If opcode == -1, the engine automatically assigns the next available opcode. handler receives (*ByteEngine, ParsedBytes).

func (*EngineUniversal) NewCommandString

func (e *EngineUniversal) NewCommandString(
	cmdSwitch string, handler core.CommandType[engine.StringEngine, stringParsing.ParsedNode], doc string,
) error

NewCommandString registers a text-based command in a StringEngine. cmdSwitch is the command name (e.g., "print"). handler must have signature func([]interface{}) error where arguments are (*StringEngine, ParsedNode). doc is an optional documentation string.

func (*EngineUniversal) ProcessBytes

func (e *EngineUniversal) ProcessBytes(input []byte) error

ProcessBytes feeds a byte slice into the engine (ByteEngineType only). The input is passed via scope under key "input_[]byte", then parsed and processed.

func (*EngineUniversal) ProcessBytesWithCtx

func (e *EngineUniversal) ProcessBytesWithCtx(input []byte, ctx context.Context) error

func (*EngineUniversal) ProcessString

func (e *EngineUniversal) ProcessString(input string) error

ProcessString feeds a string input into the engine. It works only for engines of type StringEngineType; otherwise returns an error. Internally triggers the parse and call events, executing registered handlers.

func (*EngineUniversal) ProcessStringWithCtx

func (e *EngineUniversal) ProcessStringWithCtx(input string, ctx context.Context) error

Directories

Path Synopsis
configLang2 command
tooling

Jump to

Keyboard shortcuts

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