Compare commits
No commits in common. "971a9d10d2147c88fc5e403cda51539e4762cdc3" and "32db56304bfbbfe9b61cf74282a36d4f2a0eeab0" have entirely different histories.
971a9d10d2
...
32db56304b
6 changed files with 35 additions and 139 deletions
|
@ -276,15 +276,15 @@ ApplicationWindow {
|
||||||
history.unserialize(...data["history"])
|
history.unserialize(...data["history"])
|
||||||
|
|
||||||
// Refreshing sidebar
|
// Refreshing sidebar
|
||||||
if(sidebarSelector.currentIndex == 0) {
|
//if(sidebarSelector.currentIndex == 0) {
|
||||||
// For some reason, if we load a file while the tab is on object,
|
// // For some reason, if we load a file while the tab is on object,
|
||||||
// we get stuck in a Qt-side loop? Qt bug or side-effect here, I don't know.
|
// // we get stuck in a Qt-side loop? Qt bug or side-effect here, I don't know.
|
||||||
sidebarSelector.currentIndex = 1
|
// sidebarSelector.currentIndex = 1
|
||||||
objectLists.update()
|
// objectLists.update()
|
||||||
delayRefreshTimer.start()
|
// delayRefreshTimer.start()
|
||||||
} else {
|
//} else {
|
||||||
objectLists.update()
|
objectLists.update()
|
||||||
}
|
//}
|
||||||
} else {
|
} else {
|
||||||
error = qsTr("Invalid file provided.")
|
error = qsTr("Invalid file provided.")
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,6 @@ import QtQuick 2.12
|
||||||
import QtQuick.Dialogs 1.3 as D
|
import QtQuick.Dialogs 1.3 as D
|
||||||
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
|
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
|
||||||
import "../js/mathlib.js" as MathLib
|
import "../js/mathlib.js" as MathLib
|
||||||
import "../js/utils.js" as Utils
|
|
||||||
import "../js/parsing/parsing.js" as Parsing
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -79,7 +77,6 @@ Item {
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty string ExpressionEditor::openAndCloseMatches
|
\qmlproperty string ExpressionEditor::openAndCloseMatches
|
||||||
Characters that when pressed, should be immediately followed up by their closing character.
|
Characters that when pressed, should be immediately followed up by their closing character.
|
||||||
TODO: Make it configurable.
|
|
||||||
*/
|
*/
|
||||||
readonly property var openAndCloseMatches: {
|
readonly property var openAndCloseMatches: {
|
||||||
"(": ")",
|
"(": ")",
|
||||||
|
@ -88,21 +85,6 @@ Item {
|
||||||
'"': '"'
|
'"': '"'
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
\qmlproperty string ExpressionEditor::colorScheme
|
|
||||||
Color scheme of the editor, currently based on Breeze Light.
|
|
||||||
TODO: Make it configurable.
|
|
||||||
*/
|
|
||||||
readonly property var colorScheme: {
|
|
||||||
'NORMAL': "#1F1C1B",
|
|
||||||
'VARIABLE': "#0057AE",
|
|
||||||
'CONSTANT': "#5E2F00",
|
|
||||||
'FUNCTION': "#644A9B",
|
|
||||||
'OPERATOR': "#A44EA4",
|
|
||||||
'STRING': "#9C0E0E",
|
|
||||||
'NUMBER': "#805C00"
|
|
||||||
}
|
|
||||||
|
|
||||||
Icon {
|
Icon {
|
||||||
id: iconLabel
|
id: iconLabel
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
@ -135,7 +117,6 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: editor
|
id: editor
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
@ -145,9 +126,8 @@ Item {
|
||||||
height: parent.height
|
height: parent.height
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
horizontalAlignment: control.label == "" ? TextInput.AlignLeft : TextInput.AlignHCenter
|
horizontalAlignment: control.label == "" ? TextInput.AlignLeft : TextInput.AlignHCenter
|
||||||
font.pixelSize: 14
|
|
||||||
text: control.defValue
|
text: control.defValue
|
||||||
color: "transparent"//sysPalette.windowText
|
color: sysPalette.windowText
|
||||||
focus: true
|
focus: true
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
|
|
||||||
|
@ -174,18 +154,6 @@ Item {
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
|
||||||
id: colorizedEditor
|
|
||||||
anchors.fill: editor
|
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
|
||||||
horizontalAlignment: control.label == "" ? TextInput.AlignLeft : TextInput.AlignHCenter
|
|
||||||
textFormat: Text.StyledText
|
|
||||||
text: colorize(editor.text)
|
|
||||||
color: sysPalette.windowText
|
|
||||||
font.pixelSize: parent.font.pixelSize
|
|
||||||
//opacity: editor.activeFocus ? 0 : 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
@ -242,46 +210,5 @@ Item {
|
||||||
}
|
}
|
||||||
return expr
|
return expr
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
\qmlmethod var ExpressionEditor::colorize(string expressionText)
|
|
||||||
Creates an HTML colorized string of the incomplete \c expressionText.
|
|
||||||
Returns the colorized and escaped expression if possible, null otherwise..
|
|
||||||
*/
|
|
||||||
function colorize(text) {
|
|
||||||
let tokenizer = new Parsing.Tokenizer(new Parsing.Input(text), true, false)
|
|
||||||
let parsedText = ""
|
|
||||||
let token
|
|
||||||
console.log("Parsing text:", parsedText)
|
|
||||||
while((token = tokenizer.next()) != null) {
|
|
||||||
switch(token.type) {
|
|
||||||
case Parsing.TokenType.VARIABLE:
|
|
||||||
parsedText += `<font color="${colorScheme.VARIABLE}">${token.value}</font>`
|
|
||||||
break;
|
|
||||||
case Parsing.TokenType.CONSTANT:
|
|
||||||
parsedText += `<font color="${colorScheme.CONSTANT}">${token.value}</font>`
|
|
||||||
break;
|
|
||||||
case Parsing.TokenType.FUNCTION:
|
|
||||||
parsedText += `<font color="${Utils.escapeHTML(colorScheme.FUNCTION)}">${token.value}</font>`
|
|
||||||
break;
|
|
||||||
case Parsing.TokenType.OPERATOR:
|
|
||||||
parsedText += `<font color="${colorScheme.OPERATOR}">${Utils.escapeHTML(token.value)}</font>`
|
|
||||||
break;
|
|
||||||
case Parsing.TokenType.NUMBER:
|
|
||||||
parsedText += `<font color="${colorScheme.NUMBER}">${Utils.escapeHTML(token.value)}</font>`
|
|
||||||
break;
|
|
||||||
case Parsing.TokenType.STRING:
|
|
||||||
parsedText += `<font color="${colorScheme.STRING}">${token.limitator}${Utils.escapeHTML(token.value)}${token.limitator}</font>`
|
|
||||||
break;
|
|
||||||
case Parsing.TokenType.WHITESPACE:
|
|
||||||
case Parsing.TokenType.PUNCT:
|
|
||||||
default:
|
|
||||||
parsedText += Utils.escapeHTML(token.value).replace(/ /g, ' ')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log("Parsed text:", parsedText)
|
|
||||||
return parsedText
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
.pragma library
|
.pragma library
|
||||||
|
|
||||||
.import "ast.js" as AST
|
import "ast.js" as AST
|
||||||
.import "tokenizer.js" as TK
|
import "tokenizer.js" as TK
|
||||||
|
|
||||||
|
|
||||||
class ExpressionBuilder {
|
class ExpressionBuilder {
|
||||||
|
|
|
@ -33,7 +33,7 @@ class InputExpression {
|
||||||
}
|
}
|
||||||
|
|
||||||
skip(char) {
|
skip(char) {
|
||||||
if(!this.atEnd() && this.peek() == char) {
|
if(!atEnd() && peek() == char) {
|
||||||
this.position++;
|
this.position++;
|
||||||
} else {
|
} else {
|
||||||
this.raise("Unexpected character " + peek() + ". Expected character " + char);
|
this.raise("Unexpected character " + peek() + ". Expected character " + char);
|
||||||
|
|
|
@ -22,22 +22,20 @@
|
||||||
|
|
||||||
const WHITESPACES = " \t\n\r"
|
const WHITESPACES = " \t\n\r"
|
||||||
const STRING_LIMITORS = '"\'`';
|
const STRING_LIMITORS = '"\'`';
|
||||||
const OPERATORS = "+-*/^%?:=!><";
|
const OPERATORS = "+-*/^%";
|
||||||
const PUNCTUTATION = "()[]{},.";
|
const PUNCTUTATION = "()[]{},";
|
||||||
const NUMBER_CHARS = "0123456789."
|
const NUMBER_CHARS = "0123456789."
|
||||||
const IDENTIFIER_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789_₀₁₂₃₄₅₆₇₈₉αβγδεζηθκλμξρςστφχψωₐₑₒₓₔₕₖₗₘₙₚₛₜ"
|
const IDENTIFIER_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789_₀₁₂₃₄₅₆₇₈₉αβγδεζηθκλμξρςστφχψωₐₑₒₓₔₕₖₗₘₙₚₛₜ"
|
||||||
|
|
||||||
var TokenType = {
|
enum TokenType {
|
||||||
// Expression type
|
// Expression type
|
||||||
"WHITESPACE": "WHITESPACE",
|
VARIABLE,
|
||||||
"VARIABLE": "VARIABLE",
|
CONSTANT,
|
||||||
"CONSTANT": "CONSTANT",
|
FUNCTION,
|
||||||
"FUNCTION": "FUNCTION",
|
OPERATOR,
|
||||||
"OPERATOR": "OPERATOR",
|
PUNCT,
|
||||||
"PUNCT": "PUNCT",
|
NUMBER,
|
||||||
"NUMBER": "NUMBER",
|
STRING
|
||||||
"STRING": "STRING",
|
|
||||||
"UNKNOWN": "UNKNOWN"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Token {
|
class Token {
|
||||||
|
@ -48,11 +46,9 @@ class Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExpressionTokenizer {
|
class ExpressionTokenizer {
|
||||||
constructor(input, tokenizeWhitespaces = false, errorOnUnknown = true) {
|
constructor(input) {
|
||||||
this.input = input;
|
this.input = input;
|
||||||
this.currentToken = null;
|
this.currentToken = null;
|
||||||
this.tokenizeWhitespaces = tokenizeWhitespaces
|
|
||||||
this.errorOnUnknown = errorOnUnknown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
skipWhitespaces() {
|
skipWhitespaces() {
|
||||||
|
@ -60,14 +56,6 @@ class ExpressionTokenizer {
|
||||||
this.input.next();
|
this.input.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
readWhitespaces() {
|
|
||||||
let included = "";
|
|
||||||
while(!this.input.atEnd() && WHITESPACES.includes(this.input.peek())) {
|
|
||||||
included += this.input.next();
|
|
||||||
}
|
|
||||||
return new Token(TokenType.WHITESPACE, included)
|
|
||||||
}
|
|
||||||
|
|
||||||
readString() {
|
readString() {
|
||||||
let delimitation = this.input.peek();
|
let delimitation = this.input.peek();
|
||||||
if(STRING_LIMITORS.includes(delimitation)) {
|
if(STRING_LIMITORS.includes(delimitation)) {
|
||||||
|
@ -80,9 +68,7 @@ class ExpressionTokenizer {
|
||||||
included += this.input.next();
|
included += this.input.next();
|
||||||
}
|
}
|
||||||
this.input.skip(delimitation)
|
this.input.skip(delimitation)
|
||||||
let token = new Token(TokenType.STRING, included)
|
return new Token(TokenType.STRING, included);
|
||||||
token.limitator = delimitation
|
|
||||||
return token
|
|
||||||
} else {
|
} else {
|
||||||
this.input.raise("Unexpected " + delimitation + ". Expected string delimitator")
|
this.input.raise("Unexpected " + delimitation + ". Expected string delimitator")
|
||||||
}
|
}
|
||||||
|
@ -98,20 +84,12 @@ class ExpressionTokenizer {
|
||||||
}
|
}
|
||||||
included += this.input.next();
|
included += this.input.next();
|
||||||
}
|
}
|
||||||
return new Token(TokenType.NUMBER, included)
|
|
||||||
}
|
|
||||||
|
|
||||||
readOperator() {
|
|
||||||
let included = "";
|
|
||||||
while(!this.input.atEnd() && OPERATORS.includes(this.input.peek())) {
|
|
||||||
included += this.input.next();
|
|
||||||
}
|
|
||||||
return new Token(TokenType.OPERATOR, included)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
readIdentifier() {
|
readIdentifier() {
|
||||||
let identifier = "";
|
let identifier = "";
|
||||||
while(!this.input.atEnd() && IDENTIFIER_CHARS.includes(this.input.peek().toLowerCase())) {
|
let hasDot = false;
|
||||||
|
while(!this.input.atEnd() && IDENTIFIER_CHARS.includes(this.input.peek())) {
|
||||||
identifier += this.input.next();
|
identifier += this.input.next();
|
||||||
}
|
}
|
||||||
if(Reference.CONSTANTS_LIST.includes(identifier.toLowerCase())) {
|
if(Reference.CONSTANTS_LIST.includes(identifier.toLowerCase())) {
|
||||||
|
@ -124,21 +102,16 @@ class ExpressionTokenizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
readNextToken() {
|
readNextToken() {
|
||||||
if(!this.tokenizeWhitespaces)
|
this.skipWhitespaces()
|
||||||
this.skipWhitespaces()
|
if(input.atEnd()) return null;
|
||||||
if(this.input.atEnd()) return null;
|
let c = input.peek();
|
||||||
let c = this.input.peek();
|
|
||||||
if(this.tokenizeWhitespaces && WHITESPACES.includes(c)) return this.readWhitespaces();
|
|
||||||
if(STRING_LIMITORS.includes(c)) return this.readString();
|
if(STRING_LIMITORS.includes(c)) return this.readString();
|
||||||
if(NUMBER_CHARS.includes(c)) return this.readNumber();
|
if(NUMBER_CHARS.includes(c)) return this.readNumber();
|
||||||
if(IDENTIFIER_CHARS.includes(c.toLowerCase())) return this.readIdentifier();
|
if(IDENTIFIER_CHARS.includes(c)) return this.readIdentifier();
|
||||||
if(OPERATORS.includes(c)) return this.readOperator();
|
|
||||||
if(Reference.CONSTANTS_LIST.includes(c)) return new Token(TokenType.CONSTANT, c);
|
if(Reference.CONSTANTS_LIST.includes(c)) return new Token(TokenType.CONSTANT, c);
|
||||||
if(PUNCTUTATION.includes(c)) return new Token(TokenType.PUNCT, this.input.next());
|
if(OPERATORS.includes(c)) return new Token(TokenType.OPERATOR, c);
|
||||||
if(this.errorOnUnknown)
|
if(PUNCTUTATION.includes(c)) return new Token(TokenType.PUNCT, c);
|
||||||
this.input.throw("Unknown token character " + c)
|
this.input.throw("Unknown token character " + c)
|
||||||
else
|
|
||||||
return new Token(TokenType.UNKNOWN, this.input.next());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
peek() {
|
peek() {
|
||||||
|
@ -161,8 +134,8 @@ class ExpressionTokenizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
skip(type) {
|
skip(type) {
|
||||||
let next = this.next();
|
Token next = Next();
|
||||||
if(next.type != type)
|
if(next.type != type)
|
||||||
input.raise("Unexpected token " + next.type.toLowerCase() + ' "' + next.value + '". Expected ' + type.toLowerCase());
|
input.raise("Unexpected token " + next.type.oLowerCase() + ' "' + next.value + '". Expected ' + type.toLowerCase());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -347,7 +347,3 @@ function getRandomColor() {
|
||||||
}
|
}
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeHTML(str) {
|
|
||||||
return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') ;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue