Skip to content

Commit

Permalink
Implementation of Void-token (tokay-lang#129)
Browse files Browse the repository at this point in the history
* ImlValue::(SelfToken|SelfValue|VoidToken)

* Implemented basic ImlValue::VoidToken behavior

* Context::get_capture() using Capture

* Clarify Op::Next and Op::Reject

* Clarification of VoidToken

* Let $0 always return entire range of current parselet

* Context::run() continue with end-execution only when necessary

* Drafting Until and String

* Updated ROADMAP.md
  • Loading branch information
phorward authored Jan 18, 2024
1 parent 90c396c commit 2c124ef
Show file tree
Hide file tree
Showing 14 changed files with 124 additions and 58 deletions.
9 changes: 8 additions & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,16 @@ This document describes upcoming changes to achieve with a specific version.
- [ ] `Until<P, Escape: '\\'>`
- [ ] `String<Start, End: Void, Escape: '\\'>`
- [ ] Implement inlined parselets (#120)
- [ ] New list syntax `,`, redefining sequence/`dict` syntax (#100)
- [x] New list syntax `,`, redefining sequence/`dict` syntax (#100)
- Top-level `list` definition `l = ,`
- Top-level `dict` definition `d = ()`
- [ ] Compiler refactoring and improvements
- [x] Scope-struct
- [ ] Clean-up Scope-Compiler-intermezzo
- [x] `void` and `Void`
- [x] `Empty`
- [ ] ImlRefValue
- [ ] ImlVariable

## 0.8

Expand Down
7 changes: 5 additions & 2 deletions src/builtin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,11 @@ tokay_function!("ord : @c", {

tokay_function!("print : @*args", {
if args.len() == 0 && context.is_some() {
if let Some(capture) = context.unwrap().get_capture(0) {
print!("{}", capture.to_string());
let context = context.unwrap();

if let Some(mut capture) = context.get_capture(0) {
let value = capture.extract(context.thread.reader);
print!("{}", value.to_string());
}
} else {
for i in 0..args.len() {
Expand Down
8 changes: 5 additions & 3 deletions src/compiler/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ use crate::vm::*;
use charclass::CharClass;

pub static RESERVED_TOKENS: &[&'static str] = &[
"Char", "Chars", "EOF", "Expect", "Not", "Kle", "Opt", "Peek", "Pos", "Repeat", "Self", "Void",
"Char", "Chars", "Empty", "EOF", "Expect", "Not", "Kle", "Opt", "Peek", "Pos", "Repeat",
"Self", "Void",
];

pub static RESERVED_KEYWORDS: &[&'static str] = &[
Expand Down Expand Up @@ -79,7 +80,7 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
"value_null" => ImlValue::Value(scope.compiler.statics.borrow()[1].clone()),
"value_true" => ImlValue::Value(scope.compiler.statics.borrow()[2].clone()),
"value_false" => ImlValue::Value(scope.compiler.statics.borrow()[3].clone()),
"value_self" => ImlValue::This(false),
"value_self" => ImlValue::SelfValue,
"value_integer" => match node["value"].to_i64() {
Ok(0) => ImlValue::Value(scope.compiler.statics.borrow()[4].clone()),
Ok(1) => ImlValue::Value(scope.compiler.statics.borrow()[5].clone()),
Expand All @@ -89,7 +90,8 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
"value_string" => scope.compiler.register_static(node["value"].clone()),

// Tokens
"value_token_self" => ImlValue::This(true),
"value_token_self" => ImlValue::SelfToken,
"value_token_void" => ImlValue::VoidToken,
"value_token_match" | "value_token_touch" => {
let mut value = node["value"].to_string();

Expand Down
4 changes: 2 additions & 2 deletions src/compiler/iml/imlparselet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,8 @@ impl ImlParselet {
}

match value {
ImlValue::This(_) => {
// Replace any references of self
ImlValue::SelfValue | ImlValue::SelfToken => {
// Replace any references of self by from
*value = ImlValue::Parselet(from.clone());
changes = true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/iml/imlprogram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ impl ImlProgram {
ImlValue::Unresolved(value) => {
finalize_value(&*value.borrow(), current, visited, configs)
}
ImlValue::This(_) => Some(Consumable {
ImlValue::SelfToken => Some(Consumable {
leftrec: true,
nullable: false,
}),
Expand Down
20 changes: 13 additions & 7 deletions src/compiler/iml/imlvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ modified and resolved during the compilation process.
pub(in crate::compiler) enum ImlValue {
Unset, // Unset
Unresolved(Rc<RefCell<ImlValue>>), // Unresolved ImlValues are shared
SelfValue, // self-reference (value)
SelfToken, // Self-reference (consuming)
VoidToken, // Void (consuming)
Value(RefValue), // Static value
Parselet(ImlParselet), // Parselet
This(bool), // self-reference to function (false) or parselet (true)
Variable {
// Resolved variable
offset: Option<Offset>, // Source offset
Expand Down Expand Up @@ -265,7 +267,7 @@ impl ImlValue {
pub fn is_callable(&self, without_arguments: bool) -> bool {
match self {
Self::Unresolved(value) => value.borrow().is_callable(without_arguments),
Self::This(_) => true, // fixme?
Self::SelfValue | Self::SelfToken => true, // fixme?
Self::Value(value) => value.is_callable(without_arguments),
Self::Parselet(parselet) => {
let parselet = parselet.borrow();
Expand All @@ -290,7 +292,8 @@ impl ImlValue {
pub fn is_consuming(&self) -> bool {
match self {
Self::Unresolved(value) => value.borrow().is_consuming(),
Self::This(consuming) => *consuming,
Self::SelfValue => false,
Self::SelfToken | Self::VoidToken => true,
Self::Value(value) => value.is_consuming(),
Self::Parselet(parselet) => parselet.borrow().model.borrow().is_consuming,
Self::Name { name, .. } | Self::Generic { name, .. } => {
Expand Down Expand Up @@ -325,6 +328,7 @@ impl ImlValue {
ImlValue::Unresolved(value) => {
return value.borrow().compile(program, current, offset, call, ops)
}
ImlValue::VoidToken => ops.push(Op::Next),
ImlValue::Value(value) => match &*value.borrow() {
Value::Void => ops.push(Op::PushVoid),
Value::Null => ops.push(Op::PushNull),
Expand All @@ -350,14 +354,14 @@ impl ImlValue {
return current.0.borrow().generics[name]
.compile(program, current, offset, call, ops)
}
ImlValue::This(_) | ImlValue::Parselet(_) => {}
ImlValue::SelfValue | ImlValue::SelfToken | ImlValue::Parselet(_) => {}
_ => unreachable!("{}", self),
}

// Check if something has been pushed before.
if start == ops.len() {
let idx = match self {
ImlValue::This(_) => current.1, // use current index
ImlValue::SelfValue | ImlValue::SelfToken => current.1, // use current index
ImlValue::Parselet(parselet) => match parselet.derive(current.0) {
Ok(parselet) => program.register(&ImlValue::Parselet(parselet)),
Err(msg) => {
Expand Down Expand Up @@ -404,8 +408,9 @@ impl std::fmt::Display for ImlValue {
match self {
Self::Unset => write!(f, "unset"),
Self::Unresolved(value) => value.borrow().fmt(f),
Self::This(true) => write!(f, "Self"),
Self::This(false) => write!(f, "self"),
Self::SelfValue => write!(f, "self"),
Self::SelfToken => write!(f, "Self"),
Self::VoidToken => write!(f, "Void"),
Self::Value(value) => write!(f, "{}", value.repr()),
Self::Parselet(parselet) => write!(
f,
Expand Down Expand Up @@ -460,6 +465,7 @@ impl std::hash::Hash for ImlValue {
match self {
Self::Unset => state.write_u8('u' as u8),
Self::Unresolved(value) => value.borrow().hash(state),
Self::VoidToken => state.write_u8('V' as u8),
Self::Value(value) => {
state.write_u8('v' as u8);
value.hash(state)
Expand Down
42 changes: 42 additions & 0 deletions src/compiler/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4205,6 +4205,48 @@ impl Parser {
]))
]))
]))
])),
(value!([
"emit" => "sequence",
"children" =>
(value!([
(value!([
"emit" => "value_generic",
"children" =>
(value!([
(value!([
"emit" => "identifier",
"value" => "Keyword"
])),
(value!([
"emit" => "genarg",
"children" =>
(value!([
"emit" => "value_token_touch",
"value" => "Void"
]))
]))
]))
])),
(value!([
"emit" => "call",
"children" =>
(value!([
(value!([
"emit" => "identifier",
"value" => "ast"
])),
(value!([
"emit" => "callarg",
"children" =>
(value!([
"emit" => "value_string",
"value" => "value_token_void"
]))
]))
]))
]))
]))
]))
]))
]))
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl Compiler {
])),
(value!([
"emit" => "identifier",
"value" => "Void"
"value" => "Empty"
]))
]))
]))
Expand Down Expand Up @@ -865,7 +865,7 @@ impl Compiler {
])),
(value!([
"emit" => "identifier",
"value" => "Void"
"value" => "Empty"
]))
]))
]))
Expand Down
1 change: 1 addition & 0 deletions src/compiler/tokay.tok
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ TokenLiteral : @{
Keyword<'Char'> '<' Ccl '>' ast("value_token_ccl")
Keyword<'Char'> ast("value_token_any")
Keyword<'Self'> ast("value_token_self")
Keyword<'Void'> ast("value_token_void")
}

Token : @{
Expand Down
6 changes: 3 additions & 3 deletions src/prelude.tok
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
# The `Not`-builtin runs its parser and returns its negated result,
# so that `P` occurence becomes rejected.
#
# Everything else becomes accepted (Void).
# Everything else becomes accepted (Empty).
Not : @<P> {
P reject
Void
Empty
}

# The `Peek`-builtin runs `P` and returns its result, but resets the reading-context afterwards.
Expand Down Expand Up @@ -74,7 +74,7 @@ Pos : @<P, blur: true>{ Repeat<P, blur: blur> }
Kle : @<P, blur: true>{ Repeat<P, min: 0, blur: blur> || void }

# Optionally accepts `P` or nothing.
Opt : @<P>{ P | Void }
Opt : @<P>{ P | Empty }

# Implements a recursive, separated list.
#
Expand Down
10 changes: 5 additions & 5 deletions src/value/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ extern crate self as tokay;

#[derive(Debug, Clone, Hash, PartialEq, PartialOrd)]
pub enum Token {
Void, // Matches the empty word
Empty, // Matches the empty word
EOF, // Matches End of File
Char(CharClass), // Matches one character from a character class
BuiltinChar(fn(ch: char) -> bool), // Matches one character from a callback function
Expand Down Expand Up @@ -59,8 +59,8 @@ impl Token {
}

match ident {
"Empty" => Some(Token::Empty),
"EOF" => Some(Token::EOF),
"Void" => Some(Token::Void),
ident => builtin_ccl(ident),
}
}
Expand All @@ -73,7 +73,7 @@ impl Object for Token {

fn repr(&self) -> String {
match self {
Token::Void => "Void".to_string(),
Token::Empty => "Empty".to_string(),
Token::EOF => "EOF".to_string(),
Token::Char(ccl) => format!("{:?}", ccl),
Token::Chars(ccl) => format!("{:?}+", ccl),
Expand All @@ -93,7 +93,7 @@ impl Object for Token {

fn is_nullable(&self) -> bool {
match self {
Token::Void => true,
Token::Empty => true,
Token::EOF => false,
Token::Char(ccl) | Token::Chars(ccl) => ccl.len() == 0, //True shouldn't be possible here by definition!
Token::BuiltinChar(_) | Token::BuiltinChars(_) => true,
Expand All @@ -113,7 +113,7 @@ impl Object for Token {
let reader = &mut context.thread.reader;

match self {
Token::Void => Ok(Accept::Next),
Token::Empty => Ok(Accept::Next),
Token::EOF => {
if let Some(_) = reader.peek() {
Err(Reject::Next)
Expand Down
Loading

0 comments on commit 2c124ef

Please sign in to comment.