624 lines
20 KiB
Python
624 lines
20 KiB
Python
from typing import List, Dict, Any
|
|
from .base_tests import BaseTestGenerator, Token
|
|
|
|
|
|
class TokenStringTestGenerator(BaseTestGenerator):
|
|
"""Generate test cases for token strings (unparsed code blocks in braces)."""
|
|
|
|
def generate_basic_tests(self):
|
|
"""Generate basic token string tests."""
|
|
# Empty token string
|
|
self.make_token_string_test(
|
|
"TokenString Empty",
|
|
"{ }",
|
|
[]
|
|
)
|
|
|
|
# Single token
|
|
self.make_token_string_test(
|
|
"TokenString Single Integer",
|
|
"{ 42 }",
|
|
[Token(type="i64", value=42)]
|
|
)
|
|
|
|
self.make_token_string_test(
|
|
"TokenString Single Identifier",
|
|
"{ dup }",
|
|
[Token(type="identifier", value="dup")]
|
|
)
|
|
|
|
# Two tokens
|
|
self.make_token_string_test(
|
|
"TokenString Two Integers",
|
|
"{ 2 3 }",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3)
|
|
]
|
|
)
|
|
|
|
# Simple expression
|
|
self.make_token_string_test(
|
|
"TokenString Simple Expression",
|
|
"{ 2 3 + }",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
# Stack manipulation
|
|
self.make_token_string_test(
|
|
"TokenString Stack Ops",
|
|
"{ dup * }",
|
|
[
|
|
Token(type="identifier", value="dup"),
|
|
Token(type="identifier", value="*")
|
|
]
|
|
)
|
|
|
|
def generate_literal_tests(self):
|
|
"""Generate tests with various literal types inside token strings."""
|
|
# Integer literals
|
|
self.make_token_string_test(
|
|
"TokenString Integer Literals",
|
|
"{ 0 42 -10 1000 }",
|
|
[
|
|
Token(type="i64", value=0),
|
|
Token(type="i64", value=42),
|
|
Token(type="i64", value=-10),
|
|
Token(type="i64", value=1000)
|
|
]
|
|
)
|
|
|
|
# Float literals
|
|
self.make_token_string_test(
|
|
"TokenString Float Literals",
|
|
"{ 3.14 -2.5 0.0 }",
|
|
[
|
|
Token(type="f64", value=3.14),
|
|
Token(type="f64", value=-2.5),
|
|
Token(type="f64", value=0.0)
|
|
]
|
|
)
|
|
|
|
# String literals
|
|
if self.ENABLE_STRINGS:
|
|
self.make_token_string_test(
|
|
"TokenString String Literal",
|
|
'{ "hello" }',
|
|
[Token(type="String", value="hello")]
|
|
)
|
|
|
|
self.make_token_string_test(
|
|
"TokenString Multiple Strings",
|
|
'{ "hello" "world" }',
|
|
[
|
|
Token(type="String", value="hello"),
|
|
Token(type="String", value="world")
|
|
]
|
|
)
|
|
|
|
# Character literals
|
|
self.make_token_string_test(
|
|
"TokenString Char Literal",
|
|
"{ 'A' }",
|
|
[Token(type="char", value='A')]
|
|
)
|
|
|
|
# Boolean literals
|
|
self.make_token_string_test(
|
|
"TokenString Boolean Literals",
|
|
"{ true false }",
|
|
[
|
|
Token(type="bool", value=True),
|
|
Token(type="bool", value=False)
|
|
]
|
|
)
|
|
|
|
# Mixed literals
|
|
if self.ENABLE_STRINGS:
|
|
self.make_token_string_test(
|
|
"TokenString Mixed Literals",
|
|
'{ 42 3.14 "hello" true \'A\' }',
|
|
[
|
|
Token(type="i64", value=42),
|
|
Token(type="f64", value=3.14),
|
|
Token(type="String", value="hello"),
|
|
Token(type="bool", value=True),
|
|
Token(type="char", value='A')
|
|
]
|
|
)
|
|
|
|
def generate_identifier_tests(self):
|
|
"""Generate tests with various identifiers inside token strings."""
|
|
# Multiple identifiers
|
|
self.make_token_string_test(
|
|
"TokenString Multiple Identifiers",
|
|
"{ dup swap over }",
|
|
[
|
|
Token(type="identifier", value="dup"),
|
|
Token(type="identifier", value="swap"),
|
|
Token(type="identifier", value="over")
|
|
]
|
|
)
|
|
|
|
# Identifier literals (with ::)
|
|
self.make_token_string_test(
|
|
"TokenString Identifier Literals",
|
|
"{ ::x ::y }",
|
|
[
|
|
Token(type="identifier_literal", value="x"),
|
|
Token(type="identifier_literal", value="y")
|
|
]
|
|
)
|
|
|
|
# Mixed identifiers and literals
|
|
self.make_token_string_test(
|
|
"TokenString Mixed Identifiers",
|
|
"{ ::Point get x swap }",
|
|
[
|
|
Token(type="identifier_literal", value="Point"),
|
|
Token(type="identifier", value="get"),
|
|
Token(type="identifier", value="x"),
|
|
Token(type="identifier", value="swap")
|
|
]
|
|
)
|
|
|
|
def generate_nested_tests(self):
|
|
"""Generate tests with nested token strings."""
|
|
# Single nesting
|
|
inner_tokens = [
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
inner_token_string = self.make_token_string_token(inner_tokens)
|
|
|
|
self.make_token_string_test(
|
|
"TokenString Nested Single",
|
|
"{ { 2 3 + } }",
|
|
[inner_token_string]
|
|
)
|
|
|
|
# Nested with other tokens
|
|
self.make_token_string_test(
|
|
"TokenString Nested With Others",
|
|
"{ x { dup * } }",
|
|
[
|
|
Token(type="identifier", value="x"),
|
|
self.make_token_string_token([
|
|
Token(type="identifier", value="dup"),
|
|
Token(type="identifier", value="*")
|
|
])
|
|
]
|
|
)
|
|
|
|
# Multiple nested
|
|
self.make_token_string_test(
|
|
"TokenString Multiple Nested",
|
|
"{ { 2 3 + } { 4 5 * } }",
|
|
[
|
|
self.make_token_string_token([
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]),
|
|
self.make_token_string_token([
|
|
Token(type="i64", value=4),
|
|
Token(type="i64", value=5),
|
|
Token(type="identifier", value="*")
|
|
])
|
|
]
|
|
)
|
|
|
|
# Double nesting
|
|
deepest = self.make_token_string_token([Token(type="i64", value=42)])
|
|
middle = self.make_token_string_token([deepest])
|
|
|
|
self.make_token_string_test(
|
|
"TokenString Double Nested",
|
|
"{ { { 42 } } }",
|
|
[middle]
|
|
)
|
|
|
|
# Complex nesting with mixed content
|
|
self.make_token_string_test(
|
|
"TokenString Complex Nesting",
|
|
"{ 1 { 2 { 3 } 4 } 5 }",
|
|
[
|
|
Token(type="i64", value=1),
|
|
self.make_token_string_token([
|
|
Token(type="i64", value=2),
|
|
self.make_token_string_token([
|
|
Token(type="i64", value=3)
|
|
]),
|
|
Token(type="i64", value=4)
|
|
]),
|
|
Token(type="i64", value=5)
|
|
]
|
|
)
|
|
|
|
def generate_whitespace_tests(self):
|
|
"""Generate tests with various whitespace patterns."""
|
|
# No whitespace inside
|
|
self.make_token_string_test(
|
|
"TokenString No Whitespace",
|
|
"{2 3 +}",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
# Extra whitespace
|
|
self.make_token_string_test(
|
|
"TokenString Extra Whitespace",
|
|
"{ 2 3 + }",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
# Leading whitespace outside
|
|
self.make_token_string_test(
|
|
"TokenString Leading Whitespace Outside",
|
|
" { 2 3 + }",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
# Trailing whitespace outside
|
|
self.make_token_string_test(
|
|
"TokenString Trailing Whitespace Outside",
|
|
"{ 2 3 + } ",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
# Tabs
|
|
self.make_token_string_test(
|
|
"TokenString With Tabs",
|
|
"{\\t2\\t3\\t+\\t}",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
def generate_multiline_tests(self):
|
|
"""Generate tests with multiline token strings."""
|
|
# Simple multiline
|
|
self.make_token_string_test(
|
|
"TokenString Multiline Simple",
|
|
"{\\n 2 3 +\\n}",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
# Multiple lines with tokens
|
|
self.make_token_string_test(
|
|
"TokenString Multiline Multiple",
|
|
"{\\n dup\\n *\\n 2\\n +\\n}",
|
|
[
|
|
Token(type="identifier", value="dup"),
|
|
Token(type="identifier", value="*"),
|
|
Token(type="i64", value=2),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
# Mixed line breaks
|
|
self.make_token_string_test(
|
|
"TokenString Mixed Line Breaks",
|
|
"{ 1 2\\n3 4\\n\\n5 6 }",
|
|
[
|
|
Token(type="i64", value=1),
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="i64", value=4),
|
|
Token(type="i64", value=5),
|
|
Token(type="i64", value=6)
|
|
]
|
|
)
|
|
|
|
# Indented multiline
|
|
self.make_token_string_test(
|
|
"TokenString Indented Multiline",
|
|
"{\\n dup 0 >\\n { }\\n { 0 swap - }\\n if\\n}",
|
|
[
|
|
Token(type="identifier", value="dup"),
|
|
Token(type="i64", value=0),
|
|
Token(type="identifier", value=">"),
|
|
self.make_token_string_token([]),
|
|
self.make_token_string_token([
|
|
Token(type="i64", value=0),
|
|
Token(type="identifier", value="swap"),
|
|
Token(type="identifier", value="-")
|
|
]),
|
|
Token(type="identifier", value="if")
|
|
]
|
|
)
|
|
|
|
def generate_comment_tests(self):
|
|
"""Generate tests with comments inside token strings."""
|
|
# Comment at end of line inside token string
|
|
self.make_token_string_test(
|
|
"TokenString Comment End Of Line",
|
|
"{ 2 3 + // add them\\n}",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
# Multiple comments
|
|
self.make_token_string_test(
|
|
"TokenString Multiple Comments",
|
|
"{ 2 // first\\n3 // second\\n+ // add\\n}",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
# Comment on its own line
|
|
self.make_token_string_test(
|
|
"TokenString Comment Own Line",
|
|
"{\\n // This is a comment\\n 2 3 +\\n}",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
# Comment at start
|
|
self.make_token_string_test(
|
|
"TokenString Comment At Start",
|
|
"{ // comment\\n2 3 + }",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
# Multiple comment lines
|
|
self.make_token_string_test(
|
|
"TokenString Multiple Comment Lines",
|
|
"{\\n // First comment\\n // Second comment\\n 2 3 +\\n}",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
# Comments in nested token strings
|
|
self.make_token_string_test(
|
|
"TokenString Comments Nested",
|
|
"{ { 2 3 + // inner comment\\n} // outer comment\\n}",
|
|
[
|
|
self.make_token_string_token([
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
])
|
|
]
|
|
)
|
|
|
|
def generate_error_tests(self):
|
|
"""Generate error test cases."""
|
|
# Unclosed token string
|
|
self.make_error_test(
|
|
"TokenString Unclosed",
|
|
"{ 2 3 +",
|
|
"Unclosed token string: missing closing brace '}'."
|
|
)
|
|
|
|
# Unclosed nested
|
|
self.make_error_test(
|
|
"TokenString Unclosed Nested",
|
|
"{ { 2 3 + }",
|
|
"Unclosed token string: missing closing brace '}'."
|
|
)
|
|
|
|
# Extra closing brace (generates two tokens: valid token string + error)
|
|
token = self.make_token_string_token([
|
|
Token(type="i64", value=2),
|
|
Token(type="i64", value=3),
|
|
Token(type="identifier", value="+")
|
|
])
|
|
error_token = self.make_error_token(
|
|
"Unexpected closing brace '}' without matching opening brace."
|
|
)
|
|
self.add_test(
|
|
"TokenString Extra Closing Brace",
|
|
"{ 2 3 + } }",
|
|
[token, error_token]
|
|
)
|
|
|
|
# Only closing brace
|
|
self.make_error_test(
|
|
"TokenString Only Closing Brace",
|
|
"}",
|
|
"Unexpected closing brace '}' without matching opening brace."
|
|
)
|
|
|
|
# Error inside token string (invalid literal)
|
|
error_inside = self.make_token_string_token([
|
|
Token(type="i64", value=2),
|
|
Token(type="error", value="Invalid decimal literal: unexpected 'a' in decimal integer."),
|
|
Token(type="identifier", value="+")
|
|
])
|
|
op_value = {"tokens": [
|
|
{"type": "i64", "value": 2},
|
|
{"type": "error", "value": "Invalid decimal literal: unexpected 'a' in decimal integer."},
|
|
{"type": "identifier", "value": "+"}
|
|
]}
|
|
op = self.make_push_op("token_string", op_value)
|
|
stack = self.make_stack_item("token_string", op_value)
|
|
|
|
self.add_test(
|
|
"TokenString Error Inside",
|
|
"{ 2 3a + }",
|
|
[error_inside],
|
|
[op],
|
|
[stack]
|
|
)
|
|
|
|
# Unclosed string inside token string
|
|
error_string = self.make_token_string_token([
|
|
Token(type="error", value="Invalid string literal: unclosed string literal.")
|
|
])
|
|
op_value_str = {"tokens": [
|
|
{"type": "error", "value": "Invalid string literal: unclosed string literal."}
|
|
]}
|
|
op_str = self.make_push_op("token_string", op_value_str)
|
|
stack_str = self.make_stack_item("token_string", op_value_str)
|
|
|
|
if self.ENABLE_STRINGS:
|
|
self.add_test(
|
|
"TokenString Unclosed String Inside",
|
|
'{ "hello }',
|
|
[error_string],
|
|
[op_str],
|
|
[stack_str]
|
|
)
|
|
|
|
def generate_complex_tests(self):
|
|
"""Generate complex realistic test cases."""
|
|
# Function body
|
|
self.make_token_string_test(
|
|
"TokenString Function Body",
|
|
"{ dup * }",
|
|
[
|
|
Token(type="identifier", value="dup"),
|
|
Token(type="identifier", value="*")
|
|
]
|
|
)
|
|
|
|
# If statement branches
|
|
if self.ENABLE_STRINGS:
|
|
self.make_token_string_test(
|
|
"TokenString If Branches",
|
|
'{ "positive" print }',
|
|
[
|
|
Token(type="String", value="positive"),
|
|
Token(type="identifier", value="print")
|
|
]
|
|
)
|
|
|
|
# Loop body
|
|
self.make_token_string_test(
|
|
"TokenString Loop Body",
|
|
"{ dup print 1 + }",
|
|
[
|
|
Token(type="identifier", value="dup"),
|
|
Token(type="identifier", value="print"),
|
|
Token(type="i64", value=1),
|
|
Token(type="identifier", value="+")
|
|
]
|
|
)
|
|
|
|
# Struct definition
|
|
self.make_token_string_test(
|
|
"TokenString Struct Fields",
|
|
"{ x: y: }",
|
|
[
|
|
Token(type="identifier", value="x"),
|
|
Token(type="identifier", value=":"),
|
|
Token(type="identifier", value="y"),
|
|
Token(type="identifier", value=":")
|
|
]
|
|
)
|
|
|
|
# Lambda expression
|
|
self.make_token_string_test(
|
|
"TokenString Lambda",
|
|
"{ 2 * }",
|
|
[
|
|
Token(type="i64", value=2),
|
|
Token(type="identifier", value="*")
|
|
]
|
|
)
|
|
|
|
# Array map operation
|
|
self.make_token_string_test(
|
|
"TokenString Array Map",
|
|
"{ dup * }",
|
|
[
|
|
Token(type="identifier", value="dup"),
|
|
Token(type="identifier", value="*")
|
|
]
|
|
)
|
|
|
|
# Conditional with nested token strings
|
|
self.make_token_string_test(
|
|
"TokenString Conditional Complex",
|
|
"{\\n dup 0 >\\n { dup * }\\n { drop 0 }\\n if\\n}",
|
|
[
|
|
Token(type="identifier", value="dup"),
|
|
Token(type="i64", value=0),
|
|
Token(type="identifier", value=">"),
|
|
self.make_token_string_token([
|
|
Token(type="identifier", value="dup"),
|
|
Token(type="identifier", value="*")
|
|
]),
|
|
self.make_token_string_token([
|
|
Token(type="identifier", value="drop"),
|
|
Token(type="i64", value=0)
|
|
]),
|
|
Token(type="identifier", value="if")
|
|
]
|
|
)
|
|
|
|
def generate_all_tests(self) -> List[Dict[str, Any]]:
|
|
"""Generate all token string test cases."""
|
|
# Basic tests
|
|
self.generate_basic_tests()
|
|
|
|
# Literal types
|
|
self.generate_literal_tests()
|
|
|
|
# Identifiers
|
|
self.generate_identifier_tests()
|
|
|
|
# Nested token strings
|
|
self.generate_nested_tests()
|
|
|
|
# Whitespace handling
|
|
self.generate_whitespace_tests()
|
|
|
|
# Multiline token strings
|
|
self.generate_multiline_tests()
|
|
|
|
# Comments inside token strings
|
|
self.generate_comment_tests()
|
|
|
|
# Error cases
|
|
self.generate_error_tests()
|
|
|
|
# Complex realistic cases
|
|
self.generate_complex_tests()
|
|
|
|
return self.get_tests()
|
|
|