Language Grammar Specification
This document describes the grammar rules actually implemented in the current project, based on the actual code of the project's lexer, parser, and AST structure.
Complete Grammar Specification (BNF Notation)
// Program structure
program ::= contract
// Contract definition
contract ::= "Contract" IDENTIFIER ":" NEWLINE INDENT [member]* DEDENT
member ::= function | struct | constructor
// Function definition
function ::= "def" IDENTIFIER "(" [parameter_list] ")" ["->" return_type] ":" block
constructor ::= "def" "__init__" "(" [parameter_list] ")" ":" block
parameter_list ::= parameter ["," parameter]*
parameter ::= IDENTIFIER ":" TYPE
// Struct definition
struct ::= "Struct" IDENTIFIER ":" NEWLINE INDENT [field]+ DEDENT
field ::= IDENTIFIER ":" TYPE NEWLINE
// Statements
statement ::= if_statement
| return_statement
| assignment_statement
| destructure_assignment
| variable_declaration
| expression_statement
block ::= NEWLINE INDENT [statement]* DEDENT
if_statement ::= "if" expression ":" block ["else" ":" block]
return_statement ::= "Return" expression NEWLINE
| "return" expression NEWLINE
assignment_statement ::= (IDENTIFIER | field_access) "=" expression NEWLINE
destructure_assignment ::= "{" identifier_list "}" "=" expression NEWLINE
identifier_list ::= IDENTIFIER ["," IDENTIFIER]*
variable_declaration ::= IDENTIFIER ":" TYPE ["=" expression] NEWLINE
expression_statement ::= expression NEWLINE
// Expressions
expression ::= binary_expression
| unary_expression
| primary_expression
binary_expression ::= expression binary_operator expression
unary_expression ::= unary_operator expression
primary_expression ::= IDENTIFIER
| literal
| function_call
| method_call
| field_access
| Clone_expression
| brace_expression
| "(" expression ")"
brace_expression ::= "{" [expression_list] "}"
expression_list ::= expression ["," expression]*
function_call ::= IDENTIFIER "(" [argument_list] ")"
method_call ::= expression "." IDENTIFIER "(" [argument_list] ")"
field_access ::= expression "." IDENTIFIER
clone_expression ::= IDENTIFIER "." "Clone" "(" ")"
argument_list ::= expression ["," expression]*
// Literals
literal ::= NUMBER | HEX | STRING | ADDRESS | BOOL
// Operators
binary_operator ::= "+" | "-" | "*" | "/"
| "==" | "!=" | "<" | ">" | "<=" | ">="
unary_operator ::= "-" | "+"
// Lexical elements
IDENTIFIER ::= [a-zA-Z_][a-zA-Z0-9_]*
NUMBER ::= [0-9]+
HEX ::= "0x"[0-9a-fA-F]+
STRING ::= '"' [^"]* '"'
TYPE ::= IDENTIFIER
NEWLINE ::= '\n'
INDENT ::= increase indentation level
DEDENT ::= decrease indentation level1. Program Structure
1.1 Program Definition
program ::= contractA program consists of a single contract (single-contract system).
1.2 Contract Definition
contract ::= "Contract" IDENTIFIER ":" NEWLINE INDENT [member]* DEDENT
member ::= function | struct | constructorA contract starts with the keyword Contract, followed by the contract name, using Python-style indentation.
2. Data Structures
2.1 Struct Definition
struct ::= "Struct" IDENTIFIER ":" NEWLINE INDENT [field]+ DEDENT
field ::= IDENTIFIER ":" TYPE NEWLINEA struct definition must contain at least one field; each field must have a type declaration.
Example:
Struct Person:
name: string
age: int
publicKey: hex
walletAddress: address3. Function Definitions
3.1 Regular Functions
function ::= "def" IDENTIFIER "(" [parameter_list] ")" ["->" TYPE] ":" block
parameter_list ::= parameter ["," parameter]*
parameter ::= IDENTIFIER ":" TYPEFunction parameters must include type declarations.
Example:
def main(sig: string, pubkey: hex):
result = CheckSig(pubkey, sig)
return result3.2 Constructor
constructor ::= "def" "__init__" "(" [parameter_list] ")" ":" blockThe constructor uses the special name __init__.
Example:
def __init__(pubKeyH: hex):
self.pubKeyHash = pubKeyH4. Statements
4.1 Statement Types
statement ::= if_statement
| return_statement
| assignment_statement
| variable_declaration
| expression_statement
block ::= NEWLINE INDENT [statement]* DEDENT4.2 Conditional Statements
if_statement ::= "if" expression ":" block ["else" ":" block]Example:
if _check_lock_time(current_time, timeout):
CheckSig(sender, senderSig)
else:
CheckSig(recipient, recipientSig)4.3 Return Statements
return_statement ::= "Return" expression NEWLINE
| "return" expression NEWLINE4.4 Assignment Statements
assignment_statement ::= (IDENTIFIER | field_access) "=" expression NEWLINE
field_access ::= expression "." IDENTIFIERExample:
x = 10
self.value = result
Sub.x = 04.5 Variable Declarations
variable_declaration ::= IDENTIFIER ":" TYPE ["=" expression] NEWLINEExample:
count: int
name: string = "default"
btcAddress: address = "1RainRzqJtJxHTngafpCejDLfYq2y4KBc"5. Expressions
5.1 Expression Types
expression ::= binary_expression
| unary_expression
| primary_expression
primary_expression ::= IDENTIFIER
| literal
| function_call
| method_call
| field_access
| "(" expression ")"
literal ::= NUMBER | HEX | STRING | ADDRESSLiteral type descriptions:
NUMBER: Integer literal, e.g.,42,-10HEX: Hexadecimal literal, e.g.,0xabcd,0x1234STRING: String literal, e.g.,"hello","world"BOOL: Boolean literal, e.g.,1,0ADDRESS: Bitcoin address literal; only supports Base58 P2PKH addresses starting with1, 34 characters, e.g.,"1RainRzqJtJxHTngafpCejDLfYq2y4KBc"
Example:
# Address literal example
p2pkhAddr: address = "1RainRzqJtJxHTngafpCejDLfYq2y4KBc" # P2PKH address5.2 Function Calls
function_call ::= IDENTIFIER "(" [argument_list] ")"
argument_list ::= expression ["," expression]*Example:
CheckSig(pubkey, sig)
Sha256(data)
EqualVerify(hash1, hash2)5.3 Method Calls and Field Access
method_call ::= expression "." IDENTIFIER "(" [argument_list] ")"
field_access ::= expression "." IDENTIFIERSupports chained calls:
obj.field1.field2
obj.field.method()5.4 Binary Operations
binary_expression ::= expression binary_operator expression
binary_operator ::= "+" | "-" | "*" | "/"
| "==" | "!=" | "<" | ">" | "<=" | ">="5.5 Unary Operations
unary_expression ::= unary_operator expression
unary_operator ::= "-" | "+"6. Lexical Elements
6.1 Keywords
keywords ::= "Contract" | "def" | "Struct" | "if" | "else" | "Return" | "return"6.2 Identifiers and Literals
IDENTIFIER ::= [_a-zA-Z][_a-zA-Z0-9]*
NUMBER ::= [0-9]+
HEX ::= "0x"[0-9a-fA-F]+
STRING ::= '"' [^"]* '"'
ADDRESS ::= '"' '1' [0-9a-fA-F]{33} '"'
TYPE ::= IDENTIFIER // Type identifier, e.g., int, string, hex, bool, address6.3 Operators and Delimiters
operators ::= "=" | "==" | "!=" | "<" | ">" | "<=" | ">="
| "+" | "-" | "*" | "/" | "->"
delimiters ::= "(" | ")" | "[" | "]" | ":" | "," | "."6.4 Indentation and Newlines
The language uses Python-style indentation to represent code block structure:
NEWLINE: newline characterINDENT: increase indentation levelDEDENT: decrease indentation level
7. Ownership System
The language implements an ownership concept similar to Rust, but only constrains data variables:
7.1 Ownership Rules
- Variable consumption: When a local variable is used (as a function argument, assigned to another variable, etc.), the ownership of the original variable is transferred
- Contract member variable exception: A contract's member variables (e.g.,
self.field) are directly replaced into the code at compile time, so they are not subject to ownership constraints and can be used multiple times withoutClone - Clone operation: For local variables, use
Clone()to create a copy of the variable, avoiding ownership transfer - Field access: Accessing a field of a struct instance consumes the ownership of that field; to access it multiple times, first clone it; but contract member variables are not subject to this restriction
- Special built-in functions:
SetAlt()andSetMain()do not consume variable ownership
7.2 Clone Syntax
clone_expression ::= IDENTIFIER "." "Clone" "(" ")"Example:
original_value = 42
cloned_value = original_value.Clone()
# original_value is still usable7.3 Built-in Functions
The language provides the following built-in functions:
Clone(): Creates a copy of a variable; syntax isvariable.Clone()SetAlt(variable): Moves a variable to the alt stack; does not consume variable ownershipSetMain(variable): Moves a variable from the alt stack to the main stack; does not consume variable ownership- Other built-in functions: Such as
CheckSig(),Sha256(), etc.; follow normal function call syntax and consume argument ownership
7.4 Ownership System Examples
Local variable ownership transfer:
data = Push("0x1234")
result1 = CheckSig(data, signature) # data is consumed, cannot be used again
# result2 = CheckSig(data, signature2) # Error: data has been consumed
# Need to clone to use multiple times
data2 = Push("0x5678")
cloned_data = data2.Clone()
result1 = CheckSig(data2, signature1)
result2 = CheckSig(cloned_data, signature2) # correct: using a cloned copySpecial behavior of contract member variables:
def main(sig1: string, sig2: string):
# Contract member variables can be used multiple times without Clone
result1 = CheckSig(self.pubKey, sig1)
result2 = CheckSig(self.pubKey, sig2) # correct: self.pubKey can be used repeatedly
return {result1, result2}Special built-in functions:
data: hex = "0x1234"
SetAlt(data) # data is still usable; ownership not consumed
SetMain(data) # data is still usable; ownership not consumed8. Brace Syntax Sugar ({} Syntax)
8.1 Syntax Definition
brace_expression ::= "{" [expression_list] "}"
destructure_assignment ::= "{" identifier_list "}" "=" expression NEWLINE8.2 Uses and Semantics
The brace syntax sugar {} is a multi-purpose syntax feature with different semantics depending on context:
8.2.1 Multiple Return Value Destructuring
Used to receive multiple return values from a function:
{a, b} = Split(data, 10) # Split returns two values, assigned to a and b respectively
{x, y, z} = _GetCoordinates() # receive three return values8.2.2 Struct Literals
Used to create struct instances:
Struct Point:
x: int
y: int
# Use brace syntax sugar to create a struct instance
p: Point = {10, 20}Next Steps
- Debugger User Manual — Detailed debugger feature description