Documentation
¶
Overview ¶
Package script defines RO script types, opcodes, and scope namespace constants used by the script engine.
Index ¶
- func CompileInto(src []byte, set *CompiledScriptSet) error
- func DefaultBuiltins() map[string]BuiltinFunc
- type AssignStmt
- type BinExpr
- type BlockStmt
- type BreakStmt
- type BuiltinFunc
- type CallExpr
- type CallStmt
- type CallSubStmt
- type CompiledScript
- type CompiledScriptSet
- type ContinueStmt
- type DoWhileStmt
- type Expr
- type File
- type FloatLit
- type ForStmt
- type FuncDecl
- type FuncRefStmt
- type GotoStmt
- type Host
- type IdentExpr
- type IfStmt
- type IndexExpr
- type InputStmt
- type Instruction
- type IntLit
- type LabelDecl
- type LexError
- type MenuOption
- type MenuStmt
- type NPCDef
- type NPCHeader
- type Node
- type Opcode
- type ParenExpr
- type ParseError
- type Position
- type ReturnStmt
- type SelectStmt
- type ShopDef
- type ShopItem
- type SpawnDef
- type Stmt
- type StrLit
- type SwitchCase
- type SwitchStmt
- type TernaryExpr
- type Token
- type TokenKind
- type UnaryExpr
- type VM
- type Value
- type ValueKind
- type WarpDef
- type WarpKey
- type WhileStmt
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CompileInto ¶
func CompileInto(src []byte, set *CompiledScriptSet) error
CompileInto parses src and appends every compiled block into the accumulator set. Callers that need to compile multiple files into one set (e.g. a directory of .txt files) should use this rather than Compile, which allocates a fresh set.
func DefaultBuiltins ¶
func DefaultBuiltins() map[string]BuiltinFunc
DefaultBuiltins returns a fresh map of the dialog-subset builtins, ready to hand to NewVM. Callers extend this map with phase-specific builtins (select, menu, getitem, sc_start, …) by copying it and inserting their entries.
Types ¶
type AssignStmt ¶
type AssignStmt struct {
//nolint:revive // Required by task spec.
Lhs Expr
Op string
//nolint:revive // Required by task spec.
Rhs Expr
// contains filtered or unexported fields
}
AssignStmt is `lhs = rhs` or `lhs <op>= rhs`. Op is the source-text operator (`=`, `+=`, etc.) for diagnostic fidelity; the compiler selects the matching VM opcode.
func NewAssignStmt ¶
func NewAssignStmt(lhs Expr, op string, rhs Expr, pos Position) *AssignStmt
NewAssignStmt builds an assignment statement (`lhs = rhs` or `lhs op= rhs`).
func (*AssignStmt) Pos ¶
func (s *AssignStmt) Pos() Position
Pos returns the statement's source position.
type BinExpr ¶
type BinExpr struct {
Op string
//nolint:revive // Required by task spec.
Lhs Expr
//nolint:revive // Required by task spec.
Rhs Expr
// contains filtered or unexported fields
}
BinExpr is a binary operation: `Lhs Op Rhs`. Op is the source-text operator (`+`, `-`, `==`, etc.).
func NewBinExpr ¶
NewBinExpr builds a binary operation expression.
type BlockStmt ¶
type BlockStmt struct {
Body []Stmt
// contains filtered or unexported fields
}
BlockStmt is `{ stmts... }` used as a statement. rAthena scripts do not commonly nest blocks as standalone statements, but the parser accepts them so braced bodies can appear anywhere a statement is expected (e.g. inside a case or as a macro-style wrapper).
func NewBlockStmt ¶
NewBlockStmt creates a block statement.
type BreakStmt ¶
type BreakStmt struct {
// contains filtered or unexported fields
}
BreakStmt is `break;` — exit the innermost loop or switch.
func NewBreakStmt ¶
NewBreakStmt builds a `break;` statement.
type BuiltinFunc ¶
BuiltinFunc is a script builtin invoked by OpFunc. It receives the VM (for variable access) and the already-popped, correctly-ordered argument slice, and returns a result value plus a flow control.
type CallExpr ¶
CallExpr is a function call expression. Distinguishes between builtin and user-defined functions only by name lookup at compile time.
func NewCallExpr ¶
NewCallExpr builds a function call expression.
type CallStmt ¶
CallStmt is a builtin invocation (`set`, `mes`, `warp`, ...) emitted as a statement. Args holds the parsed argument expressions; the Name is resolved to a builtin at compile time.
func NewCallStmt ¶
NewCallStmt builds a builtin call statement.
type CallSubStmt ¶
CallSubStmt is `callsub Label, args...;`.
func NewCallSubStmt ¶
func NewCallSubStmt(label string, args []Expr, pos Position) *CallSubStmt
NewCallSubStmt builds a `callsub Label, args...;` statement.
func (*CallSubStmt) Pos ¶
func (s *CallSubStmt) Pos() Position
Pos returns the statement's source position.
type CompiledScript ¶
type CompiledScript struct {
Name string
Instructions []Instruction
Labels map[string]int
}
CompiledScript is the bytecode for a single NPC script or named function script. Labels maps label names to the instruction index of the OpLabel that introduces them; the compiler backpatches OpGoto/OpCallSub/CFunc targets through this map.
func NewCompiledScript ¶
func NewCompiledScript(name string) *CompiledScript
NewCompiledScript returns an empty CompiledScript with an initialized Labels map. Use this rather than a struct literal to guarantee the map is non-nil so label inserts don't panic.
func (*CompiledScript) LookupLabel ¶
func (c *CompiledScript) LookupLabel(name string) (int, bool)
LookupLabel returns the instruction index for a label and whether the label was found.
type CompiledScriptSet ¶
type CompiledScriptSet struct {
Scripts map[string]*CompiledScript
Funcs map[string]*CompiledScript
Warps []WarpDef
Shops []ShopDef
// NPCs records the placement of every placed (non-floating) dialog NPC,
// in compile order. The world seeder turns each into a spawned NPC
// entity registered under its script name.
NPCs []NPCDef
Spawns []SpawnDef
MapName string
}
CompiledScriptSet is the immutable set of all compiled scripts at a snapshot in time. The script engine swaps an atomic.Pointer[CompiledScriptSet] to hot-reload new versions without interrupting in-flight VMs (per design decision D-003).
func Compile ¶
func Compile(src []byte) (*CompiledScriptSet, error)
Compile is the top-level entry: parse src, compile every block, and return a CompiledScriptSet keyed by NPC name with warps/shops extracted from headers. Floating `function script` blocks land in Funcs; placed/floating NPC blocks land in Scripts under the NPC name.
func NewCompiledScriptSet ¶
func NewCompiledScriptSet() *CompiledScriptSet
NewCompiledScriptSet returns an empty set with all maps initialized.
type ContinueStmt ¶
type ContinueStmt struct {
// contains filtered or unexported fields
}
ContinueStmt is `continue;` — restart the innermost loop.
func NewContinueStmt ¶
func NewContinueStmt(pos Position) *ContinueStmt
NewContinueStmt builds a `continue;` statement.
func (*ContinueStmt) Pos ¶
func (s *ContinueStmt) Pos() Position
Pos returns the statement's source position.
type DoWhileStmt ¶
DoWhileStmt is `do { ... } while (cond);`.
func NewDoWhileStmt ¶
func NewDoWhileStmt(body []Stmt, cond Expr, pos Position) *DoWhileStmt
NewDoWhileStmt builds a `do { ... } while (cond);` statement.
func (*DoWhileStmt) Pos ¶
func (s *DoWhileStmt) Pos() Position
Pos returns the statement's source position.
type Expr ¶
type Expr interface {
Node
// contains filtered or unexported methods
}
Expr is an expression node. Expressions yield a Value when evaluated.
type File ¶
File represents a parsed script file: a tab-separated NPC header (possibly nil for floating `function script` definitions) followed by a list of body statements. For `shop` NPCs the body is empty and ShopItems carries the comma-separated item table instead.
func NewFile ¶
NewFile builds a File with the given header, body, and optional shop items. Header may be nil for floating function-script definitions. ShopItems are used by `shop` NPCs (which have no dialog body).
func Parse ¶
Parse tokenizes src with Lex and parses every top-level NPC block it contains, returning one *File per block. A block is a placed NPC (`map,x,y,dir script Name sprite,{ ... }`), a floating script (`- script Name -1,{ ... }`), or a function script (`function script Name { ... }`). Whitespace and comments are already gone by the time the parser sees the token stream.
type FloatLit ¶
type FloatLit struct {
Value float64
// contains filtered or unexported fields
}
FloatLit is a float literal. Rare in rAthena scripts.
func NewFloatLit ¶
NewFloatLit builds a floating-point literal expression.
type ForStmt ¶
type ForStmt struct {
Init []Stmt
Cond Expr
Post []Stmt
Body []Stmt
// contains filtered or unexported fields
}
ForStmt is `for (init; cond; post) { ... }`. Each clause is a slice because the for-init grammar allows comma-separated statements.
func NewForStmt ¶
NewForStmt builds a `for (init; cond; post) { ... }` statement.
type FuncDecl ¶
FuncDecl is `function script F_Name { ... }` — a global function definition. Stored in CompiledScriptSet.Funcs.
func NewFuncDecl ¶
NewFuncDecl builds a `function script Name { ... }` declaration.
type FuncRefStmt ¶
type FuncRefStmt struct {
Name string
// contains filtered or unexported fields
}
FuncRefStmt is `function F_Name;` — a forward or backward reference to a function defined elsewhere. It has no body and is compiled as a no-op; it merely marks that the name is reachable.
func NewFuncRefStmt ¶
func NewFuncRefStmt(name string, pos Position) *FuncRefStmt
NewFuncRefStmt builds a `function Name;` reference statement.
func (*FuncRefStmt) Pos ¶
func (s *FuncRefStmt) Pos() Position
Pos returns the statement's source position.
type GotoStmt ¶
type GotoStmt struct {
Label string
// contains filtered or unexported fields
}
GotoStmt is `goto Label;`.
func NewGotoStmt ¶
NewGotoStmt builds a `goto Label;` statement.
type Host ¶
type Host interface {
// Mes sends one dialog line (ZC_SCRIPT). Does not block.
Mes(msg string)
// Next sends the "click Next" prompt and blocks until the client
// advances the dialog. Returns false if the dialog was closed or the
// connection dropped, in which case the VM ends the script.
Next() bool
// Select sends the menu option list (ZC_MENU_LIST) and blocks until the
// client chooses. options is the flat list (colon-separated inputs are
// split by the builtin before calling). Returns the 1-based index the
// client picked, or 255 (FF_CANCEL) for cancel, mirroring rAthena's
// @menu / sd->npc_menu result of clif_parse_NpcSelectMenu.
Select(options []string) int
// Input sends the numeric-input dialog (ZC_OPEN_EDITDLG) and blocks until
// the client replies with CZ_INPUT_EDITDLG. Returns the entered amount and
// false if the dialog was closed or the connection dropped, in which case
// the VM ends the script — mirroring Next()'s false return.
Input() (amount int64, ok bool)
// InputStr sends the string-input dialog (ZC_OPEN_EDITDLGSTR) and blocks
// until the client replies with CZ_INPUT_EDITDLGSTR. Returns the entered
// text and false if the dialog was closed or the connection dropped.
InputStr() (text string, ok bool)
// Close sends the close-dialog frame (ZC_CLOSE_DIALOG).
Close()
// Warp moves the player to the named map tile.
Warp(mapName string, x, y int)
// PercentHeal restores HP/SP by the given percentages (0–100).
PercentHeal(hpPct, spPct int)
// GetItem grants amount units of nameID. Returns false when the bag is
// full / the item cannot be added.
GetItem(nameID uint32, amount int) bool
// DelItem removes amount units of nameID. Returns false when the player
// does not hold at least `amount` of it.
DelItem(nameID uint32, amount int) bool
// CountItem returns the player's count of nameID.
CountItem(nameID uint32) int
// Equip equips the item at the inventory index to the given slot bitmask.
// Returns false when the index is invalid.
Equip(index int, slot uint32) bool
// Unequip clears the equip bitmask of the item at the inventory index.
// Returns false when the index is invalid or the item is not equipped.
Unequip(index int) bool
// GetQuestVar returns the persistent NPC-variable value (npcName, varName)
// for the dialog's player. An unset variable reads as 0 — matches
// rAthena's "unset integer reads as 0". The persistence port is implemented
// by the content bounded context's QuestService; nil disables the
// getvariableofnpc builtin (returns 0).
GetQuestVar(npcName, varName string) int64
// SetQuestVar stores the persistent NPC-variable value (npcName, varName)
// for the dialog's player. A write error is returned to the caller; the VM
// stops with ctrlEnd on a hard write failure (mismatching the rAthena
// behaviour where a quest-table failure logs but does not abort the
// script). nil disables the persistence side of the builtin.
SetQuestVar(npcName, varName string, value int64) error
}
Host is the seam between the VM and the game server. The dialog builtins produce output here and may block the VM goroutine: Next() suspends the script until the client sends CZ_REQ_NEXT_SCRIPT, then returns. This is the goroutine-per-dialog model — the script's sequential state lives on the goroutine stack, so no manual IP serialization is needed across the wait. Effects (warp/heal) flow back through the Host to the world module.
type IdentExpr ¶
type IdentExpr struct {
Name string
// contains filtered or unexported fields
}
IdentExpr is a variable reference, possibly prefixed (`.@`, `@`, `#`, `$`, `'`) and possibly suffixed with `$` for string variables. Name preserves the source text exactly.
func NewIdentExpr ¶
NewIdentExpr builds an identifier/variable reference expression.
type IfStmt ¶
IfStmt is `if (cond) { ... } else { ... }`. Else may be nil.
type IndexExpr ¶
IndexExpr is `target[index]` — array element access. High 32 bits of the variable id encode the index (per rAthena reference_uid).
func NewIndexExpr ¶
NewIndexExpr builds an array index expression (`target[index]`).
type InputStmt ¶
type InputStmt struct {
Dst Expr
// contains filtered or unexported fields
}
InputStmt is `input @var;` — read an integer from the player into a variable.
func NewInputStmt ¶
NewInputStmt builds an `input var;` statement.
type Instruction ¶
Instruction is a single VM instruction. The Operand and Str fields carry the opcode-specific payload:
- Operand is the int payload for OpInt (literal), OpLine (line number), and numeric label indices.
- Str is the string payload for OpStr (string literal), OpVar (variable name), OpName (label/variable name), OpFunc (function name), OpLabel/OpGoto/OpCallSub (label name).
Both fields are present on every Instruction for simplicity; OpXXX constants that do not use a field leave it zero-valued.
Pos is the source location the instruction was compiled from. The VM uses it to format stack traces; the parser uses it to attach errors during compilation.
func (Instruction) String ¶
func (i Instruction) String() string
String returns a disassembly-style line for debug printing.
type IntLit ¶
type IntLit struct {
Value int64
// contains filtered or unexported fields
}
IntLit is an integer literal. Value is the parsed int64.
type LabelDecl ¶
type LabelDecl struct {
Name string
// contains filtered or unexported fields
}
LabelDecl is `L_Name:` — a label declaration. Standalone (not part of a `case`) and recognized at parse time.
func NewLabelDecl ¶
NewLabelDecl builds a label declaration (`L_Name:`).
type LexError ¶
LexError is returned by Lex when the source contains a tokenization error (unterminated string, unexpected byte, etc.). It carries the source position of the failure so errors can be surfaced with line + column context.
type MenuOption ¶
MenuOption is one entry of a menu/select/prompt. Label is the jump target; the parser accepts either a bare identifier or a `callsub L` form via CallExpr.Name.
func NewMenuOption ¶
func NewMenuOption(prompt Expr, label string, pos Position) MenuOption
NewMenuOption builds one prompt/label pair for menu/select.
func (*MenuOption) Pos ¶
func (m *MenuOption) Pos() Position
Pos returns the option's source position. Implements Node.
type MenuStmt ¶
type MenuStmt struct {
Options []MenuOption
// contains filtered or unexported fields
}
MenuStmt is `menu("optA",L_a,"optB",L_b,...);` — pair-encoded options. Each option pairs a string prompt with a label or callsub target.
func NewMenuStmt ¶
func NewMenuStmt(opts []MenuOption, pos Position) *MenuStmt
NewMenuStmt builds a `menu(...);` statement.
type NPCDef ¶
NPCDef is a placed dialog NPC: where it stands and the sprite the client renders. The script body lives in Scripts[Name].
type NPCHeader ¶
type NPCHeader struct {
MapName string
X int
Y int
Facing int
Name string
SpriteName string
SpriteID int
TriggerX int
TriggerY int
Type string
// contains filtered or unexported fields
}
NPCHeader is the tab-separated NPC definition header. It captures every column of rAthena's npc_parsename layout (npc.cpp:3668).
func NewNPCHeader ¶
func NewNPCHeader(mapName string, x, y, facing int, name, spriteName string, spriteID, triggerX, triggerY int, typ string, pos Position, ) *NPCHeader
NewNPCHeader builds an NPCHeader at the given source position.
type Node ¶
type Node interface {
Pos() Position
// contains filtered or unexported methods
}
Node is the root interface for all AST nodes. Every AST node knows its source position so that error messages and runtime diagnostics can point to the offending construct.
type Opcode ¶
type Opcode uint8
Opcode is a VM operation code. It mirrors rAthena's c_op enum (rathena/src/map/script.hpp:222-265) but uses snake_case Go names and a compact 46-entry layout suitable for an Opcode uint8.
The mapping is intentionally pragmatic, not byte-for-byte: rAthena distinguishes e.g. C_FUNC (builtin marker) from C_USERFUNC (user function marker); here both are subsumed under OpFunc with a name lookup deciding the kind at compile time. C_POS, C_NAME, C_USERFUNC_POS collapse to OpLabel with a name operand.
Wire-level bytecode, when it is emitted by the compiler, will use a uint8 discriminant followed by the per-op operand layout described on each constant below.
const ( // OpEOF marks the end of the bytecode stream. Halts the VM. OpEOF Opcode = iota // OpExpr is a unary expression evaluation marker. Operand = none. OpExpr // OpExpr2 is a binary expression evaluation marker. Operand = none. OpExpr2 // OpLAnd is logical AND short-circuit: pops 2, pushes bool. Operand = none. OpLAnd // OpLOr is logical OR short-circuit: pops 2, pushes bool. Operand = none. OpLOr // OpLEq is `==` equality. Pops 2, pushes bool. Operand = none. OpLEq // OpLNe is `!=` inequality. Pops 2, pushes bool. Operand = none. OpLNe // OpLGT is `>` greater-than. Operand = none. OpLGT // OpLLT is `<` less-than. Operand = none. OpLLT // OpLGE is `>=` greater-or-equal. Operand = none. OpLGE // OpLLE is `<=` less-or-equal. Operand = none. OpLLE // OpAdd is `+` arithmetic. Operand = none. OpAdd // OpSub is `-` arithmetic. Operand = none. OpSub // OpMul is `*` arithmetic. Operand = none. OpMul // OpDiv is `/` arithmetic. Operand = none. OpDiv // OpMod is `%` remainder. Operand = none. OpMod // OpNeg is unary `-`. Operand = none. OpNeg // OpNot is unary `!`. Operand = none. OpNot // OpAnd is bitwise `&`. Operand = none. OpAnd // OpOr is bitwise `|`. Operand = none. OpOr // OpXor is bitwise `^`. Operand = none. OpXor // OpBNot is unary bitwise `~`. Operand = none. OpBNot // OpShiftL is `<<`. Operand = none. OpShiftL // OpShiftR is `>>`. Operand = none. OpShiftR // OpAssign is `=`. Operand = none. OpAssign // OpAssignAdd is `+=`. Operand = none. OpAssignAdd // OpAssignSub is `-=`. Operand = none. OpAssignSub // OpAssignMul is `*=`. Operand = none. OpAssignMul // OpAssignDiv is `/=`. Operand = none. OpAssignDiv // OpAssignMod is `%=`. Operand = none. OpAssignMod // OpAssignShiftL is `<<=`. Operand = none. OpAssignShiftL // OpAssignShiftR is `>>=`. Operand = none. OpAssignShiftR // OpLabel marks a label definition / target. Operand = label name // (look up via CompiledScript.Labels). OpLabel // OpGoto is unconditional jump to label. Operand = label name. OpGoto // OpCallSub is a same-script label call (push return info + jump). // Operand = label name. OpCallSub // OpReturn returns from the current callsub/callfunc scope. // Operand = none. OpReturn // OpBinary marks a binary op boundary for argument-list emission // (`C_ARG` analogue in rAthena). Operand = none. // // Phase R0 (S1) also reuses OpBinary as the array-READ operator: // when the compiler emits an IndexExpr over an IdentExpr target, it // pushes the array name as a string and the index as an int, then // OpBinary pops both and resolves to the stored value via // ScopeStore.GetArray. The Str field of the instruction itself is // not used by this path. OpBinary // OpPush pushes a constant value onto the stack. The constant's // discriminant is implicit in the Instruction's Str/Operand fields. OpPush // OpVar is a variable reference (resolve by Str to a scope-backed // storage handle). Operand = Str field = variable name. OpVar // OpFunc invokes a built-in function. Operand = Str field = function // name (resolved via the BuiltinRegistry at compile time). OpFunc // OpName references a symbol by name (label, variable, function). // Operand = Str field = name. Used for argument-list name binding. OpName // OpEnd ends the current script activation. Operand = none. OpEnd // OpClose closes the player dialog. Operand = none. OpClose // OpInt is an int64 literal. Operand int32 field = value. OpInt // OpStr is a string literal. Operand Str field = decoded string. OpStr // OpLine is a line-number marker for stack-trace diagnostics. // Operand int32 field = 1-indexed source line. OpLine // OpIndexGet is the array-READ operator. Reserved for parity with // rAthena's C_GETINDEX / OpIndexGet split; the current compiler // emits OpBinary for reads and the VM handles both opcodes the // same way. // // Stack contract: pops idx (top) then name (string), pushes the // stored array element (zero Value when the array or index is // absent). OpIndexGet // OpIndexSet is the array-WRITE operator. Operand Str field = name. // // Stack contract: pops name (top), idx (second), value (third), // then stores value into ScopeStore.SetArray(name, idx). OpIndexSet // OpJumpIfFalse pops a value; if it is falsy (IsZero) the VM jumps to // the instruction index named by the Str field (resolved through // CompiledScript.Labels). Otherwise execution falls through. Used to // compile if/while/for conditions and `&&` short-circuit. The popped // value is consumed either way. OpJumpIfFalse // OpJumpIfTrue is the dual of OpJumpIfFalse: pops a value and jumps to // the Str-named label only when the value is truthy. Used to compile // `||` short-circuit. OpJumpIfTrue // OpPop discards the top of the stack. A builtin call in statement // position (e.g. `mes "x";`) leaves its return value on the stack via // OpFunc; the compiler emits OpPop so the void result does not leak. // Expression-position calls (e.g. `select(...)`) keep the value for the // surrounding expression and emit no OpPop. OpPop )
type ParenExpr ¶
type ParenExpr struct {
Inner Expr
// contains filtered or unexported fields
}
ParenExpr is `(expr)` — preserved for source-fidelity in error messages but usually collapsed by the parser.
func NewParenExpr ¶
NewParenExpr builds a parenthesized expression (`(expr)`).
type ParseError ¶
ParseError carries the source position of a syntax failure. Its format mirrors LexError so callers render parse and lex errors uniformly.
func (*ParseError) Error ¶
func (e *ParseError) Error() string
type Position ¶
Position represents a source code position (line + column).
Line is 1-indexed; Column is 1-indexed (number of characters since the most recent line start). Column counts bytes, not runes — rAthena script sources are virtually always ASCII/EUC-KR which is single-byte.
type ReturnStmt ¶
type ReturnStmt struct {
Value Expr
// contains filtered or unexported fields
}
ReturnStmt is `return [value];`.
func NewReturnStmt ¶
func NewReturnStmt(value Expr, pos Position) *ReturnStmt
NewReturnStmt builds a `return [value];` statement.
func (*ReturnStmt) Pos ¶
func (s *ReturnStmt) Pos() Position
Pos returns the statement's source position.
type SelectStmt ¶
type SelectStmt struct {
Options []MenuOption
// contains filtered or unexported fields
}
SelectStmt is `select("...");` — like menu but the index is returned rather than jumping to a label.
func NewSelectStmt ¶
func NewSelectStmt(opts []MenuOption, pos Position) *SelectStmt
NewSelectStmt builds a `select(...);` statement.
func (*SelectStmt) Pos ¶
func (s *SelectStmt) Pos() Position
Pos returns the statement's source position.
type ShopDef ¶
type ShopDef struct {
Name string
MapName string
X int
Y int
Facing int
Sprite int
Items []ShopItem
}
ShopDef defines a shop NPC: the dialog routes into a merchant UI listing Items.
type SpawnDef ¶
type SpawnDef struct {
MapName string
X int
Y int
XSize int
YSize int
Class int32
Name string
Amount int
Delay1 int
Delay2 int
}
SpawnDef is one monster-spawn line (`map,x,y[,xs,ys] monster Name class,amount[,d1,d2]`). Amount mobs spawn inside the xs×ys cell box centered on (X,Y); d1/d2 bound the respawn delay window in seconds (rAthena: respawn after d1 + rand(d2-d1)).
func ParseSpawnLines ¶
ParseSpawnLines extracts monster-spawn definitions from rAthena mob-spawn script text (`npc/pre-re/mobs/**.txt`). These files are not NPC scripts: each data line is
map,x,y[,xs,ys]<TAB>monster|boss_monster|mini<TAB>Name<TAB>class,amount[,d1,d2]
and the full NPC grammar rejects them, so this scanner runs as a fallback for files that fail Compile. Comment (`//`) and blank lines are skipped; lines that do not match are skipped rather than erroring — the corpus is large and heterogeneous, and a single odd line must not drop a file's spawns (mirrors the tolerant-loader doctrine in ADR-0003).
type Stmt ¶
type Stmt interface {
Node
// contains filtered or unexported methods
}
Stmt is a statement node. Statements never appear in expression position; they have side effects.
type StrLit ¶
type StrLit struct {
Value string
// contains filtered or unexported fields
}
StrLit is a string literal. Value is the decoded string with escape sequences resolved.
type SwitchCase ¶
SwitchCase is one arm of a switch. Values may be empty for the default case.
func NewSwitchCase ¶
func NewSwitchCase(values []Expr, body []Stmt, pos Position) SwitchCase
NewSwitchCase builds one case/default arm of a switch.
func (*SwitchCase) Pos ¶
func (sc *SwitchCase) Pos() Position
Pos returns the case's source position. Implements Node.
type SwitchStmt ¶
type SwitchStmt struct {
Value Expr
Cases []SwitchCase
// contains filtered or unexported fields
}
SwitchStmt is `switch (val) { case X: ...; default: ...; }`. The parser lowers case labels to internal labels per rAthena.
func NewSwitchStmt ¶
func NewSwitchStmt(val Expr, cases []SwitchCase, pos Position) *SwitchStmt
NewSwitchStmt builds a `switch (val) { ... }` statement.
func (*SwitchStmt) Pos ¶
func (s *SwitchStmt) Pos() Position
Pos returns the statement's source position.
type TernaryExpr ¶
TernaryExpr is `Cond ? Then : Else`. Lowered to OpExpr2 / OpLOr branch at compile time, but kept as a first-class AST node so error messages name it directly.
func NewTernaryExpr ¶
func NewTernaryExpr(cond, then, els Expr, pos Position) *TernaryExpr
NewTernaryExpr builds a conditional expression (`cond ? then : else`).
func (*TernaryExpr) Pos ¶
func (e *TernaryExpr) Pos() Position
Pos returns the expression's source position.
type Token ¶
Token is a single lexical unit produced by the scanner.
Pos is the source location of the first character of Value. For TokenEOF the position is the line/column immediately after the last consumed byte.
func Lex ¶
Lex tokenizes a rAthena script source buffer and returns the resulting token stream, terminated by TokenEOF. It returns an error only for unrecoverable lexing errors (unterminated string literal, unterminated block comment, or an unknown byte the scanner cannot classify). Whitespace and comments are silently skipped.
The lexer is a pure function: it does not retain references to the input buffer after returning. Tests can Lex a buffer, capture the tokens, and discard the buffer.
type TokenKind ¶
type TokenKind int
TokenKind classifies a lexical token.
The set covers what a hand-written recursive-descent parser for the rAthena dialect needs to see. Comments and (most) whitespace are silently dropped by the lexer; newlines are tracked implicitly via the Position carried on each Token rather than being emitted as separate tokens, except inside switch/case dispatch where they are significant only as statement separators (`;`).
const ( // TokenEOF is the sentinel emitted after the last byte of input. TokenEOF TokenKind = iota // TokenIdent is an identifier: variable, function, label name, // builtin name. The first character may be a scope prefix // (`.`, `@`, `#`, `$`, `'`) and the last character may be `$` // to mark a string-typed variable. Examples: `mes`, `.@var`, // `callfunc`, `L_Open`, `#account$`. TokenIdent // TokenInt is a decimal or hexadecimal integer literal. // Unary minus is NOT part of the literal — it is emitted as a // separate TokenOperator applied as a prefix unary. TokenInt // TokenFloat is a floating-point literal. Rare in rAthena scripts // but defined for forward compatibility with the rAthena parser. TokenFloat // TokenString is a `"..."` string literal. The Value field holds // the *decoded* string with escape sequences resolved; the raw // text is not preserved. TokenString // TokenKeyword is a reserved word: if, else, while, for, do, // switch, case, default, break, continue, function, return, goto, // callsub, callfunc, end, close, close2, next, mes, menu, select, // input, set, setarray, etc. TokenKeyword // TokenOperator is a non-assignment operator: +, -, *, /, %, // ==, !=, <, >, <=, >=, &&, ||, !, &, |, ^, ~, <<, >>, ++, --. TokenOperator // TokenAssign is an assignment operator: =, +=, -=, *=, /=, %=, // &=, |=, ^=, <<=, >>=. TokenAssign // TokenDelim is a delimiter: ; , : ( ) { } [ ] ?. TokenDelim // TokenComment is a `// line` or `/* block */` comment. Comments // are typically suppressed by the scanner but the kind exists // for diagnostics/debugging output. TokenComment // TokenNewline is emitted when the scanner observes a `\n` that // is significant for downstream parsing (e.g. to count lines). By // default the lexer skips newlines silently and the Position on // subsequent tokens carries the line number. TokenNewline )
type UnaryExpr ¶
UnaryExpr is a prefix unary operation: `Op Operand`. Op is one of `-`, `!`, `~`, `++`, `--`.
func NewUnaryExpr ¶
NewUnaryExpr builds a prefix or postfix unary expression.
type VM ¶
type VM struct {
// contains filtered or unexported fields
}
VM is a stack machine executing one CompiledScript. A fresh VM is created per dialog invocation; its goroutine owns its stack, IP, call stack, and temporary variables. The variable scope (vars) is the caller's — seeded with char vars before Run and read back after to persist changes — so the VM itself stays stateless across invocations.
func NewVM ¶
func NewVM(cs *CompiledScript, host Host, builtins map[string]BuiltinFunc, vars map[string]Value) *VM
NewVM constructs a VM for cs. host is the I/O seam, builtins resolves OpFunc names (DefaultBuiltins covers the dialog subset), and vars is the initial variable scope (may be nil). After Run, mutated vars remain in the same map for the caller to persist.
func (*VM) GetVar ¶
GetVar returns a variable's value. An unset variable yields the zero Value (nil), which IsZero reports as false and asInt reads as 0 — matching rAthena's "unset integer reads as 0".
func (*VM) Run ¶
Run executes bytecode until OpEOF, a ctrlEnd builtin (end/close), or an error. Jumps set ip and continue the loop; every other op advances ip by one at the loop tail.
type Value ¶
Value is a runtime script value. Only the field matching Kind is meaningful; the others stay zero. Value is immutable in practice — assignment replaces the whole cell, not a field of it.
func NilVal ¶
func NilVal() Value
NilVal is the absent/zero value, returned for unset variables and void calls.
func (Value) IsZero ¶
IsZero reports whether v is the falsy value for a conditional. rAthena treats 0, the empty string, and nil as false; any nonzero int, non-empty string, or any float (including 0.0, matching rAthena's float branch which is truthy unless it is the integer-zero representation) as true. Scripts overwhelmingly branch on integer results, so the int branch is the hot path.
type ValueKind ¶
type ValueKind uint8
ValueKind discriminates the dynamic type of a script Value. rAthena's script language is loosely typed: a variable holds either an integer or a string (the `$` suffix on a name marks the string cell). Float is rare but defined for forward compatibility. The VM never auto-coerces across kinds except where a builtin explicitly does (e.g. string concat).
const ( // KindNil is the zero value: an unset variable or an absent result. KindNil ValueKind = iota // KindInt is a 64-bit integer — the overwhelmingly common case. KindInt // KindStr is a UTF-8 string (variable cells suffixed `$`). KindStr // KindFloat is a 64-bit float; reserved, few builtins produce it. KindFloat )
type WarpDef ¶
type WarpDef struct {
MapName string
X int
Y int
TriggerX int
TriggerY int
DestMap string
DestX int
DestY int
}
WarpDef defines a warp portal: clicking the source tile teleports the player to DestMap/DestX/DestY.
type WhileStmt ¶
WhileStmt is `while (cond) { ... }`.
func NewWhileStmt ¶
NewWhileStmt builds a `while (cond) { ... }` statement.