mirror of
https://github.com/PaddiM8/kalker.git
synced 2024-12-12 17:40:52 +01:00
Add keywords 'true', 'false' and 'not'
This commit is contained in:
parent
f7d9f6c0d9
commit
0209f18248
@ -105,7 +105,7 @@ impl Highlighter for LineHighlighter {
|
|||||||
|
|
||||||
let reg = Regex::new(
|
let reg = Regex::new(
|
||||||
r"(?x)
|
r"(?x)
|
||||||
(?P<op>([+\-/*%^!×÷⋅∧∨ᵀ]|if|otherwise|\sand|\sor|\smod|load|exit|clear|help)) |
|
(?P<op>([+\-/*%^!×÷⋅∧∨¬ᵀ]|if|otherwise|\b(and|or|mod|true|false|not)\b|load|exit|clear|help)) |
|
||||||
(?P<radix>0[box][a-zA-Z0-9]+) |
|
(?P<radix>0[box][a-zA-Z0-9]+) |
|
||||||
(?P<identifier>[^!-@\s_|^⌊⌋⌈⌉\[\]\{\}⟦⟧≠≥≤⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎ᵀ]+(_\d+)?)",
|
(?P<identifier>[^!-@\s_|^⌊⌋⌈⌉\[\]\{\}⟦⟧≠≥≤⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎ᵀ]+(_\d+)?)",
|
||||||
)
|
)
|
||||||
@ -159,6 +159,7 @@ lazy_static! {
|
|||||||
m.insert("<=", "≤");
|
m.insert("<=", "≤");
|
||||||
m.insert(" and", " ∧");
|
m.insert(" and", " ∧");
|
||||||
m.insert(" or", " ∨");
|
m.insert(" or", " ∨");
|
||||||
|
m.insert(" not", " ¬");
|
||||||
m.insert("*", "×");
|
m.insert("*", "×");
|
||||||
m.insert("/", "÷");
|
m.insert("/", "÷");
|
||||||
m.insert("^T", "ᵀ");
|
m.insert("^T", "ᵀ");
|
||||||
@ -194,6 +195,14 @@ impl Completer for RLHelper {
|
|||||||
return Ok((pos - key.len(), vec![value.to_string()]));
|
return Ok((pos - key.len(), vec![value.to_string()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the key starts with a space, it should also be expanded
|
||||||
|
// if it is at the start of the line. To do this, the strings
|
||||||
|
// are compared with the space removed in these situations.
|
||||||
|
if key.starts_with(' ') && slice.len() == key.len() - 1 && slice == &key[1..] {
|
||||||
|
let value = &(*COMPLETION_FUNCS.get(key).unwrap())[1..];
|
||||||
|
return Ok((pos - (key.len() - 1), vec![value.to_string()]));
|
||||||
|
}
|
||||||
|
|
||||||
let mut subscript_digits = String::new();
|
let mut subscript_digits = String::new();
|
||||||
for c in slice.chars().rev() {
|
for c in slice.chars().rev() {
|
||||||
if c.is_digit(10) {
|
if c.is_digit(10) {
|
||||||
|
@ -212,7 +212,7 @@ fn analyse_expr(context: &mut Context, expr: Expr) -> Result<Expr, KalkError> {
|
|||||||
Expr::Var(identifier) => analyse_var(context, identifier, None, None)?,
|
Expr::Var(identifier) => analyse_var(context, identifier, None, None)?,
|
||||||
Expr::Group(value) => Expr::Group(Box::new(analyse_expr(context, *value)?)),
|
Expr::Group(value) => Expr::Group(Box::new(analyse_expr(context, *value)?)),
|
||||||
Expr::FnCall(identifier, arguments) => analyse_fn(context, identifier, arguments)?,
|
Expr::FnCall(identifier, arguments) => analyse_fn(context, identifier, arguments)?,
|
||||||
Expr::Literal(_) => expr,
|
Expr::Literal(_) | Expr::Boolean(_) => expr,
|
||||||
Expr::Piecewise(pieces) => {
|
Expr::Piecewise(pieces) => {
|
||||||
let mut analysed_pieces = Vec::new();
|
let mut analysed_pieces = Vec::new();
|
||||||
for piece in pieces {
|
for piece in pieces {
|
||||||
|
@ -20,6 +20,7 @@ pub enum Expr {
|
|||||||
Group(Box<Expr>),
|
Group(Box<Expr>),
|
||||||
FnCall(Identifier, Vec<Expr>),
|
FnCall(Identifier, Vec<Expr>),
|
||||||
Literal(f64),
|
Literal(f64),
|
||||||
|
Boolean(bool),
|
||||||
Piecewise(Vec<ConditionalPiece>),
|
Piecewise(Vec<ConditionalPiece>),
|
||||||
Vector(Vec<Expr>),
|
Vector(Vec<Expr>),
|
||||||
Matrix(Vec<Vec<Expr>>),
|
Matrix(Vec<Vec<Expr>>),
|
||||||
|
@ -23,7 +23,7 @@ pub enum KalkError {
|
|||||||
VariableReferencesItself,
|
VariableReferencesItself,
|
||||||
PiecewiseConditionsAreFalse,
|
PiecewiseConditionsAreFalse,
|
||||||
EvaluationError(String),
|
EvaluationError(String),
|
||||||
UnexpectedToken(TokenKind, TokenKind),
|
UnexpectedToken(TokenKind, Option<TokenKind>),
|
||||||
UnexpectedType(String, Vec<String>),
|
UnexpectedType(String, Vec<String>),
|
||||||
UndefinedFn(String),
|
UndefinedFn(String),
|
||||||
UndefinedVar(String),
|
UndefinedVar(String),
|
||||||
@ -66,7 +66,11 @@ impl ToString for KalkError {
|
|||||||
KalkError::PiecewiseConditionsAreFalse => String::from("All the conditions in the piecewise are false."),
|
KalkError::PiecewiseConditionsAreFalse => String::from("All the conditions in the piecewise are false."),
|
||||||
KalkError::EvaluationError(msg) => format!("Evaluation error: {}", msg),
|
KalkError::EvaluationError(msg) => format!("Evaluation error: {}", msg),
|
||||||
KalkError::UnexpectedToken(got, expected) => {
|
KalkError::UnexpectedToken(got, expected) => {
|
||||||
format!("Unexpected token: '{:?}', expected '{:?}'.", got, expected)
|
if let Some(expected) = expected {
|
||||||
|
format!("Unexpected token: '{:?}', expected '{:?}'.", got, expected)
|
||||||
|
} else {
|
||||||
|
format!("Unexpected token: '{:?}'.", got)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
KalkError::UnexpectedType(got, expected) => {
|
KalkError::UnexpectedType(got, expected) => {
|
||||||
format!("Unexpected type. Got {:?} but expected: {:?}.", got, expected.join(", "))
|
format!("Unexpected type. Got {:?} but expected: {:?}.", got, expected.join(", "))
|
||||||
|
@ -126,6 +126,7 @@ pub(crate) fn eval_expr(
|
|||||||
Expr::Unit(identifier, expr) => eval_unit_expr(context, identifier, expr),
|
Expr::Unit(identifier, expr) => eval_unit_expr(context, identifier, expr),
|
||||||
Expr::Var(identifier) => eval_var_expr(context, identifier, unit),
|
Expr::Var(identifier) => eval_var_expr(context, identifier, unit),
|
||||||
Expr::Literal(value) => eval_literal_expr(context, *value, unit),
|
Expr::Literal(value) => eval_literal_expr(context, *value, unit),
|
||||||
|
Expr::Boolean(value) => Ok(KalkValue::Boolean(*value)),
|
||||||
Expr::Group(expr) => eval_group_expr(context, expr, unit),
|
Expr::Group(expr) => eval_group_expr(context, expr, unit),
|
||||||
Expr::FnCall(identifier, expressions) => {
|
Expr::FnCall(identifier, expressions) => {
|
||||||
eval_fn_call_expr(context, identifier, expressions, unit)
|
eval_fn_call_expr(context, identifier, expressions, unit)
|
||||||
@ -209,6 +210,10 @@ fn eval_unary_expr(
|
|||||||
|
|
||||||
match op {
|
match op {
|
||||||
TokenKind::Minus => num.mul(context, KalkValue::from(-1f64)),
|
TokenKind::Minus => num.mul(context, KalkValue::from(-1f64)),
|
||||||
|
TokenKind::Not => match num {
|
||||||
|
KalkValue::Boolean(boolean) => Ok(KalkValue::Boolean(!boolean)),
|
||||||
|
_ => Err(KalkError::InvalidOperator),
|
||||||
|
},
|
||||||
TokenKind::Percent => num.mul(context, KalkValue::from(0.01f64)),
|
TokenKind::Percent => num.mul(context, KalkValue::from(0.01f64)),
|
||||||
TokenKind::Exclamation => prelude::special_funcs::factorial(num),
|
TokenKind::Exclamation => prelude::special_funcs::factorial(num),
|
||||||
_ => Err(KalkError::InvalidOperator),
|
_ => Err(KalkError::InvalidOperator),
|
||||||
|
@ -85,7 +85,7 @@ fn invert(
|
|||||||
arguments,
|
arguments,
|
||||||
unknown_var,
|
unknown_var,
|
||||||
),
|
),
|
||||||
Expr::Literal(_) => Ok((target_expr, expr.clone())),
|
Expr::Literal(_) | Expr::Boolean(_) => Ok((target_expr, expr.clone())),
|
||||||
Expr::Piecewise(_) => Err(KalkError::UnableToInvert(String::from("Piecewise"))),
|
Expr::Piecewise(_) => Err(KalkError::UnableToInvert(String::from("Piecewise"))),
|
||||||
Expr::Vector(_) => Err(KalkError::UnableToInvert(String::from("Vector"))),
|
Expr::Vector(_) => Err(KalkError::UnableToInvert(String::from("Vector"))),
|
||||||
Expr::Matrix(_) => Err(KalkError::UnableToInvert(String::from("Matrix"))),
|
Expr::Matrix(_) => Err(KalkError::UnableToInvert(String::from("Matrix"))),
|
||||||
@ -391,7 +391,7 @@ pub fn contains_var(symbol_table: &SymbolTable, expr: &Expr, var_name: &str) ->
|
|||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
Expr::Literal(_) => false,
|
Expr::Literal(_) | Expr::Boolean(_) => false,
|
||||||
Expr::Piecewise(_) => true, // Let it try to invert this. It will just display the error message.
|
Expr::Piecewise(_) => true, // Let it try to invert this. It will just display the error message.
|
||||||
Expr::Vector(items) => items
|
Expr::Vector(items) => items
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -25,6 +25,9 @@ pub enum TokenKind {
|
|||||||
LessOrEquals,
|
LessOrEquals,
|
||||||
And,
|
And,
|
||||||
Or,
|
Or,
|
||||||
|
Not,
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
|
||||||
UnitKeyword,
|
UnitKeyword,
|
||||||
ToKeyword,
|
ToKeyword,
|
||||||
@ -153,6 +156,7 @@ impl<'a> Lexer<'a> {
|
|||||||
'<' => build(TokenKind::LessThan, "", span),
|
'<' => build(TokenKind::LessThan, "", span),
|
||||||
'∧' => build(TokenKind::And, "", span),
|
'∧' => build(TokenKind::And, "", span),
|
||||||
'∨' => build(TokenKind::Or, "", span),
|
'∨' => build(TokenKind::Or, "", span),
|
||||||
|
'¬' => build(TokenKind::Not, "", span),
|
||||||
',' => build(TokenKind::Comma, "", span),
|
',' => build(TokenKind::Comma, "", span),
|
||||||
':' => build(TokenKind::Colon, "", span),
|
':' => build(TokenKind::Colon, "", span),
|
||||||
';' => build(TokenKind::Semicolon, "", span),
|
';' => build(TokenKind::Semicolon, "", span),
|
||||||
@ -324,6 +328,9 @@ impl<'a> Lexer<'a> {
|
|||||||
let kind = match value.as_ref() {
|
let kind = match value.as_ref() {
|
||||||
"and" => TokenKind::And,
|
"and" => TokenKind::And,
|
||||||
"or" => TokenKind::Or,
|
"or" => TokenKind::Or,
|
||||||
|
"not" => TokenKind::Not,
|
||||||
|
"true" => TokenKind::True,
|
||||||
|
"false" => TokenKind::False,
|
||||||
"mod" => TokenKind::Percent,
|
"mod" => TokenKind::Percent,
|
||||||
"unit" => TokenKind::UnitKeyword,
|
"unit" => TokenKind::UnitKeyword,
|
||||||
"to" => TokenKind::ToKeyword,
|
"to" => TokenKind::ToKeyword,
|
||||||
@ -391,7 +398,7 @@ fn is_valid_identifier(c: Option<&char>) -> bool {
|
|||||||
match c {
|
match c {
|
||||||
'+' | '-' | '/' | '*' | '%' | '^' | '!' | '(' | ')' | '=' | '.' | ',' | ';' | '|'
|
'+' | '-' | '/' | '*' | '%' | '^' | '!' | '(' | ')' | '=' | '.' | ',' | ';' | '|'
|
||||||
| '⌊' | '⌋' | '⌈' | '⌉' | '[' | ']' | '{' | '}' | 'π' | '√' | 'τ' | 'ϕ' | 'Γ' | '<'
|
| '⌊' | '⌋' | '⌈' | '⌉' | '[' | ']' | '{' | '}' | 'π' | '√' | 'τ' | 'ϕ' | 'Γ' | '<'
|
||||||
| '>' | '≠' | '≥' | '≤' | '×' | '÷' | '⋅' | '⟦' | '⟧' | '∧' | '∨' | ':' | 'ᵀ'
|
| '>' | '≠' | '≥' | '≤' | '×' | '÷' | '⋅' | '⟦' | '⟧' | '∧' | '∨' | '¬' | ':' | 'ᵀ'
|
||||||
| '\n' => false,
|
| '\n' => false,
|
||||||
_ => !c.is_digit(10) || is_superscript(c) || is_subscript(c),
|
_ => !c.is_digit(10) || is_superscript(c) || is_subscript(c),
|
||||||
}
|
}
|
||||||
|
@ -454,6 +454,7 @@ fn parse_exponent(context: &mut Context) -> Result<Expr, KalkError> {
|
|||||||
if match_token(context, TokenKind::Power) {
|
if match_token(context, TokenKind::Power) {
|
||||||
let op = advance(context).kind;
|
let op = advance(context).kind;
|
||||||
let right = Box::new(parse_exponent(context)?);
|
let right = Box::new(parse_exponent(context)?);
|
||||||
|
|
||||||
return Ok(Expr::Binary(Box::new(left), op, right));
|
return Ok(Expr::Binary(Box::new(left), op, right));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,9 +462,10 @@ fn parse_exponent(context: &mut Context) -> Result<Expr, KalkError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_unary(context: &mut Context) -> Result<Expr, KalkError> {
|
fn parse_unary(context: &mut Context) -> Result<Expr, KalkError> {
|
||||||
if match_token(context, TokenKind::Minus) {
|
if match_token(context, TokenKind::Minus) || match_token(context, TokenKind::Not) {
|
||||||
let op = advance(context).kind;
|
let op = advance(context).kind;
|
||||||
let expr = Box::new(parse_unary(context)?);
|
let expr = Box::new(parse_unary(context)?);
|
||||||
|
|
||||||
return Ok(Expr::Unary(op, expr));
|
return Ok(Expr::Unary(op, expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,7 +513,15 @@ fn parse_primary(context: &mut Context) -> Result<Expr, KalkError> {
|
|||||||
TokenKind::Pipe | TokenKind::OpenCeil | TokenKind::OpenFloor => parse_group_fn(context)?,
|
TokenKind::Pipe | TokenKind::OpenCeil | TokenKind::OpenFloor => parse_group_fn(context)?,
|
||||||
TokenKind::Identifier => parse_identifier(context)?,
|
TokenKind::Identifier => parse_identifier(context)?,
|
||||||
TokenKind::Literal => Expr::Literal(string_to_num(&advance(context).value)?),
|
TokenKind::Literal => Expr::Literal(string_to_num(&advance(context).value)?),
|
||||||
_ => return Err(KalkError::UnableToParseExpression),
|
TokenKind::True => {
|
||||||
|
advance(context);
|
||||||
|
Expr::Boolean(true)
|
||||||
|
}
|
||||||
|
TokenKind::False => {
|
||||||
|
advance(context);
|
||||||
|
Expr::Boolean(false)
|
||||||
|
}
|
||||||
|
_ => return Err(KalkError::UnexpectedToken(peek(context).kind, None)),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
@ -713,7 +723,7 @@ fn consume(context: &mut Context, kind: TokenKind) -> Result<&Token, KalkError>
|
|||||||
return Ok(advance(context));
|
return Ok(advance(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(KalkError::UnexpectedToken(peek(context).kind, kind))
|
Err(KalkError::UnexpectedToken(peek(context).kind, Some(kind)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_at_end(context: &Context) -> bool {
|
fn is_at_end(context: &Context) -> bool {
|
||||||
@ -728,7 +738,7 @@ fn skip_newlines(context: &mut Context) {
|
|||||||
|
|
||||||
fn string_to_num(value: &str) -> Result<f64, KalkError> {
|
fn string_to_num(value: &str) -> Result<f64, KalkError> {
|
||||||
let base = get_base(value)?;
|
let base = get_base(value)?;
|
||||||
if let Some(result) = crate::radix::parse_float_radix(&value.replace(" ", ""), base) {
|
if let Some(result) = crate::radix::parse_float_radix(&value.replace(' ', ""), base) {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
} else {
|
} else {
|
||||||
Err(KalkError::InvalidNumberLiteral(value.into()))
|
Err(KalkError::InvalidNumberLiteral(value.into()))
|
||||||
|
@ -48,8 +48,8 @@
|
|||||||
"svelte-preprocess": "^4.6.1",
|
"svelte-preprocess": "^4.6.1",
|
||||||
"terser-webpack-plugin": "^4.2.3",
|
"terser-webpack-plugin": "^4.2.3",
|
||||||
"ts-loader": "^8.0.2",
|
"ts-loader": "^8.0.2",
|
||||||
"ts-node": "^9.0.0",
|
"ts-node": "^10.8.0",
|
||||||
"typescript": "^4.1.2",
|
"typescript": "^4.7.2",
|
||||||
"webpack": "^4.44.1",
|
"webpack": "^4.44.1",
|
||||||
"webpack-cli": "^3.3.12",
|
"webpack-cli": "^3.3.12",
|
||||||
"webpack-dev-server": "^3.11.0"
|
"webpack-dev-server": "^3.11.0"
|
||||||
@ -61,4 +61,4 @@
|
|||||||
"browserslist": [
|
"browserslist": [
|
||||||
"defaults"
|
"defaults"
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -310,7 +310,7 @@
|
|||||||
let result = input;
|
let result = input;
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
result = result.replace(
|
result = result.replace(
|
||||||
/(?<power>\^[0-9T])|(?<brackets>\[\[)|(?<radix>0[box][a-zA-Z0-9]+)|(?<comparison>(!=|[<>]=?))|(?<html>[<>&]|(\n\s*\}?|\s+))|(?<op>([+\-/*%^!≈×÷⋅∧∨ᵀ]|if|otherwise|and|or|mod)|(?<identifier>[^!-@\s_|^⌊⌋⌈⌉≈\[\]\{\}⟦⟧≠≥≤⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎×÷⋅∧∨ᵀ]+(_\d+)?)\(?)/g,
|
/(?<power>\^[0-9T])|(?<brackets>\[\[)|(?<radix>0[box][a-zA-Z0-9]+)|(?<comparison>(!=|[<>]=?))|(?<html>[<>&]|(\n\s*\}?|\s+))|(?<op>([+\-/*%^!≈×÷⋅∧∨¬ᵀ]|if|otherwise|and|or|mod|true|false|not)|(?<identifier>[^!-@\s_|^⌊⌋⌈⌉≈\[\]\{\}⟦⟧≠≥≤⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎×÷⋅∧∨ᵀ]+(_\d+)?)\(?)/g,
|
||||||
(
|
(
|
||||||
substring,
|
substring,
|
||||||
power,
|
power,
|
||||||
@ -395,6 +395,7 @@
|
|||||||
if (substring == "/") substring = "÷";
|
if (substring == "/") substring = "÷";
|
||||||
if (substring == "and") substring = "∧";
|
if (substring == "and") substring = "∧";
|
||||||
if (substring == "or") substring = "∨";
|
if (substring == "or") substring = "∨";
|
||||||
|
if (substring == "not") substring = "¬";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (identifier) {
|
if (identifier) {
|
||||||
|
Loading…
Reference in New Issue
Block a user