Compare commits

..

No commits in common. "6116ffe4e7370f5867e6d2f23fb8832d314edcfe" and "29e62fee6ee82ee6eb2c6d7953eeabb8f26f5bfd" have entirely different histories.

6 changed files with 70 additions and 116 deletions

View file

@ -272,15 +272,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()
// delayRefreshTimer.start()
//} else {
objectLists.update() objectLists.update()
//} delayRefreshTimer.start()
} else {
objectLists.update()
}
} else { } else {
error = qsTr("Invalid file provided.") error = qsTr("Invalid file provided.")
} }

View file

@ -36,7 +36,7 @@ import "../../js/mathlib.js" as MathLib
\sa Dialog \sa Dialog
*/ */
Repeater { Repeater {
id: root id: dlgCustomProperties
signal changed() signal changed()
@ -90,52 +90,21 @@ Repeater {
} }
} }
onChanged: function(newValue) { onChanged: function(newValue) {
try { var newValue = {
var newValueParsed = { 'Expression': () => new MathLib.Expression(newValue),
'Expression': () => { 'Domain': () => MathLib.parseDomain(newValue),
let expr = new MathLib.Expression(newValue) 'string': () => newValue,
// Check if the expression is valid, throws error otherwise. 'number': () => parseFloat(newValue)
if(!expr.allRequirementsFullfilled()) { }[propertyType]()
let undefVars = expr.undefinedVariables() // Ensuring old and new values are different to prevent useless adding to history.
console.log(JSON.stringify(undefVars), undefVars.join(', ')) if(obj[propertyName] != newValue) {
if(undefVars.length > 1) history.addToHistory(new HistoryLib.EditedProperty(
throw new Error(qsTranslate('error', 'No object found with names %1.').arg(undefVars.join(', '))) obj.name, objType, propertyName,
else obj[propertyName], newValue
throw new Error(qsTranslate('error', 'No object found with name %1.').arg(undefVars.join(', '))) ))
} obj[propertyName] = newValue
if(expr.requiredObjects().includes(obj.name)) Objects.currentObjects[objType][objIndex].update()
throw new Error(qsTranslate('error', 'Object cannot be dependent on itself.')) objectListList.update()
// TODO: Check for recursive dependencies.
return expr
},
'Domain': () => MathLib.parseDomain(newValue),
'string': () => newValue,
'number': () => parseFloat(newValue)
}[propertyType]()
// Ensuring old and new values are different to prevent useless adding to history.
if(obj[propertyName] != newValueParsed) {
history.addToHistory(new HistoryLib.EditedProperty(
obj.name, objType, propertyName,
obj[propertyName], newValueParsed
))
obj[propertyName] = newValueParsed
root.changed()
}
} catch(e) {
// Error in expression or domain
parsingErrorDialog.showDialog(propertyName, newValue, e.message)
}
}
D.MessageDialog {
id: parsingErrorDialog
title: qsTr("LogarithmPlotter - Parsing error")
text: ""
function showDialog(propName, propValue, error) {
text = qsTr("Error while parsing expression for property %1:\n%2\n\nEvaluated expression: %3").arg(propName).arg(error).arg(propValue)
open()
} }
} }
} }
@ -157,7 +126,8 @@ Repeater {
obj[propertyName], this.checked obj[propertyName], this.checked
)) ))
obj[propertyName] = this.checked obj[propertyName] = this.checked
root.changed() Objects.currentObjects[objType][objIndex].update()
objectListList.update()
} }
} }
} }
@ -217,7 +187,8 @@ Repeater {
obj[propertyName] = baseModel[newIndex] obj[propertyName] = baseModel[newIndex]
} }
// Refreshing // Refreshing
root.changed() Objects.currentObjects[objType][objIndex].update()
objectListList.update()
} }
} }
} }
@ -246,7 +217,9 @@ Repeater {
)) ))
//Objects.currentObjects[objType][objIndex][propertyName] = exported //Objects.currentObjects[objType][objIndex][propertyName] = exported
obj[propertyName] = exported obj[propertyName] = exported
root.changed() //Objects.currentObjects[objType][objIndex].update()
obj.update()
objectListList.update()
} }
Component.onCompleted: { Component.onCompleted: {

View file

@ -120,7 +120,6 @@ D.Dialog {
onActivated: function(newIndex) { onActivated: function(newIndex) {
if(idModel[newIndex] != objEditor.obj.labelContent) { if(idModel[newIndex] != objEditor.obj.labelContent) {
objEditor.obj.labelContent = idModel[newIndex] objEditor.obj.labelContent = idModel[newIndex]
objEditor.obj.update()
objectListList.update() objectListList.update()
} }
} }
@ -130,11 +129,6 @@ D.Dialog {
CustomPropertyList { CustomPropertyList {
id: dlgCustomProperties id: dlgCustomProperties
obj: objEditor.obj obj: objEditor.obj
onChanged: {
obj.update()
objectListList.update()
}
} }
} }

View file

@ -144,6 +144,7 @@ Item {
ToolTip.text: qsTr("Set %1 %2 position").arg(obj.constructor.displayType()).arg(obj.name) ToolTip.text: qsTr("Set %1 %2 position").arg(obj.constructor.displayType()).arg(obj.name)
onClicked: { onClicked: {
console.log(obj.type, obj.name)
posPicker.objType = obj.type posPicker.objType = obj.type
posPicker.objName = obj.name posPicker.objName = obj.name
posPicker.pickX = hasXProp posPicker.pickX = hasXProp

View file

@ -18,16 +18,16 @@ var IARRAY = 'IARRAY';
// Additional variable characters. // Additional variable characters.
var ADDITIONAL_VARCHARS = [ var ADDITIONAL_VARCHARS = [
"α","β","γ","δ","ε","ζ","η", "α","β","γ","δ","ε","ζ","η",
"π","θ","κ","λ","μ","ξ","ρ", "π","θ","κ","λ","μ","ξ","ρ",
"ς","σ","τ","φ","χ","ψ","ω", "ς","σ","τ","φ","χ","ψ","ω",
"Γ","Δ","Θ","Λ","Ξ","Π","Σ", "Γ","Δ","Θ","Λ","Ξ","Π","Σ",
"Φ","Ψ","Ω","ₐ","ₑ","ₒ","ₓ", "Φ","Ψ","Ω","ₐ","ₑ","ₒ","ₓ",
"ₕ","ₖ","ₗ","ₘ","ₙ","ₚ","ₛ", "ₕ","ₖ","ₗ","ₘ","ₙ","ₚ","ₛ",
"ₜ","¹","²","³","⁴","⁵","⁶", "ₜ","¹","²","³","⁴","⁵","⁶",
"⁷","⁸","⁹","⁰","₁","₂","₃", "⁷","⁸","⁹","⁰","₁","₂","₃",
"₄","₅","₆","₇","₈","₉","₀" "₄","₅","₆","₇","₈","₉","₀"
] ]
function Instruction(type, value) { function Instruction(type, value) {
this.type = type; this.type = type;
@ -117,11 +117,7 @@ function simplify(tokens, unaryOps, binaryOps, ternaryOps, values) {
newexpression.push(new Instruction(IEXPR, simplify(item.value, unaryOps, binaryOps, ternaryOps, values))); newexpression.push(new Instruction(IEXPR, simplify(item.value, unaryOps, binaryOps, ternaryOps, values)));
} else if (type === IMEMBER && nstack.length > 0) { } else if (type === IMEMBER && nstack.length > 0) {
n1 = nstack.pop(); n1 = nstack.pop();
//console.log("Getting property ", item.value, "of", n1) nstack.push(new Instruction(INUMBER, n1.value[item.value]));
if(item.value in n1.value)
nstack.push(new Instruction(INUMBER, n1.value[item.value]));
else
throw new Error(qsTranslate('error', 'Cannot find property %1 of object %2.').arg(item.value).arg(n1))
} /* else if (type === IARRAY && nstack.length >= item.value) { } /* else if (type === IARRAY && nstack.length >= item.value) {
var length = item.value; var length = item.value;
while (length-- > 0) { while (length-- > 0) {
@ -221,7 +217,7 @@ function evaluate(tokens, expr, values) {
if (v !== undefined) { if (v !== undefined) {
nstack.push(v); nstack.push(v);
} else { } else {
throw new Error(qsTranslate('error', 'Undefined variable %1.').arg(item.value)); throw new Error('undefined variable: ' + item.value);
} }
} }
} else if (type === IOP1) { } else if (type === IOP1) {
@ -241,7 +237,7 @@ function evaluate(tokens, expr, values) {
// Objects & expressions execution // Objects & expressions execution
nstack.push(f.execute.apply(f, args)); nstack.push(f.execute.apply(f, args));
} else { } else {
throw new Error(qsTranslate('error', '%1 cannot be executed.').arg(f)); throw new Error(f + ' cannot be executed');
} }
} else if (type === IFUNDEF) { } else if (type === IFUNDEF) {
// Create closure to keep references to arguments and expression // Create closure to keep references to arguments and expression
@ -274,11 +270,7 @@ function evaluate(tokens, expr, values) {
nstack.push(item); nstack.push(item);
} else if (type === IMEMBER) { } else if (type === IMEMBER) {
n1 = nstack.pop(); n1 = nstack.pop();
//console.log("Getting property", item.value, "of", n1) nstack.push(n1[item.value]);
if(item.value in n1)
nstack.push(n1[item.value]);
else
throw new Error(qsTranslate('error', 'Cannot find property %1 of object %2.').arg(item.value).arg(n1))
} else if (type === IENDSTATEMENT) { } else if (type === IENDSTATEMENT) {
nstack.pop(); nstack.pop();
} else if (type === IARRAY) { } else if (type === IARRAY) {
@ -289,11 +281,11 @@ function evaluate(tokens, expr, values) {
} }
nstack.push(args); nstack.push(args);
} else { } else {
throw new Error(qsTranslate('error', 'Invalid expression.')); throw new Error('invalid Expression');
} }
} }
if (nstack.length > 1) { if (nstack.length > 1) {
throw new Error(qsTranslate('error', 'Invalid expression (parity).')); throw new Error('invalid Expression (parity)');
} }
// Explicitly return zero to avoid test issues caused by -0 // Explicitly return zero to avoid test issues caused by -0
return nstack[0] === 0 ? 0 : resolveExpression(nstack[0], values); return nstack[0] === 0 ? 0 : resolveExpression(nstack[0], values);
@ -369,7 +361,7 @@ function expressionToString(tokens, toJS) {
if (f === '?') { if (f === '?') {
nstack.push('(' + n1 + ' ? ' + n2 + ' : ' + n3 + ')'); nstack.push('(' + n1 + ' ? ' + n2 + ' : ' + n3 + ')');
} else { } else {
throw new Error(qsTranslate('error', 'Invalid expression.')); throw new Error('invalid Expression');
} }
} else if (type === IVAR || type === IVARNAME) { } else if (type === IVAR || type === IVARNAME) {
nstack.push(item.value); nstack.push(item.value);
@ -425,7 +417,7 @@ function expressionToString(tokens, toJS) {
} else if (type === IEXPR) { } else if (type === IEXPR) {
nstack.push('(' + expressionToString(item.value, toJS) + ')'); nstack.push('(' + expressionToString(item.value, toJS) + ')');
} else if (type === IENDSTATEMENT) ; else { } else if (type === IENDSTATEMENT) ; else {
throw new Error(qsTranslate('error', 'Invalid expression.')); throw new Error('invalid Expression');
} }
} }
if (nstack.length > 1) { if (nstack.length > 1) {
@ -613,7 +605,7 @@ TokenStream.prototype.next = function () {
this.isName()) { this.isName()) {
return this.current; return this.current;
} else { } else {
this.parseError(qsTranslate('error', 'Unknown character "%1".').arg(this.expression.charAt(this.pos))); this.parseError('Unknown character "' + this.expression.charAt(this.pos) + '"');
} }
}; };
@ -807,13 +799,13 @@ TokenStream.prototype.unescape = function (v) {
// interpret the following 4 characters as the hex of the unicode code point // interpret the following 4 characters as the hex of the unicode code point
var codePoint = v.substring(index + 1, index + 5); var codePoint = v.substring(index + 1, index + 5);
if (!codePointPattern.test(codePoint)) { if (!codePointPattern.test(codePoint)) {
this.parseError(qsTranslate('error', 'Illegal escape sequence: %1.').arg("\\u" + codePoint)); this.parseError('Illegal escape sequence: \\u' + codePoint);
} }
buffer += String.fromCharCode(parseInt(codePoint, 16)); buffer += String.fromCharCode(parseInt(codePoint, 16));
index += 4; index += 4;
break; break;
default: default:
throw this.parseError(qsTranslate('error', 'Illegal escape sequence: %1.').arg('\\' + c)); throw this.parseError('Illegal escape sequence: "\\' + c + '"');
} }
++index; ++index;
var backslash = v.indexOf('\\', index); var backslash = v.indexOf('\\', index);
@ -1015,7 +1007,7 @@ TokenStream.prototype.getCoordinates = function () {
TokenStream.prototype.parseError = function (msg) { TokenStream.prototype.parseError = function (msg) {
var coords = this.getCoordinates(); var coords = this.getCoordinates();
throw new Error(qsTranslate('error', 'Parse error [%1:%2]: %3').arg(coords.line).arg(coords.column).arg(msg)); throw new Error('parse error [' + coords.line + ':' + coords.column + ']: ' + msg);
}; };
function ParserState(parser, tokenStream, options) { function ParserState(parser, tokenStream, options) {
@ -1069,9 +1061,7 @@ ParserState.prototype.accept = function (type, value) {
ParserState.prototype.expect = function (type, value) { ParserState.prototype.expect = function (type, value) {
if (!this.accept(type, value)) { if (!this.accept(type, value)) {
var coords = this.tokens.getCoordinates(); var coords = this.tokens.getCoordinates();
throw new Error(qsTranslate('error', 'Parse error [%1:%2]: %3') throw new Error('parse error [' + coords.line + ':' + coords.column + ']: Expected ' + (value || type));
.arg(coords.line).arg(coords.column)
.arg(qsTranslate('error', 'Expected %1').arg(qsTranslate('error',value) || type)));
} }
}; };
@ -1098,7 +1088,7 @@ ParserState.prototype.parseAtom = function (instr) {
instr.push(new Instruction(IARRAY, argCount)); instr.push(new Instruction(IARRAY, argCount));
} }
} else { } else {
throw new Error(qsTranslate('error', 'Unexpected %1').arg(this.nextToken)); throw new Error('unexpected ' + this.nextToken);
} }
}; };
@ -1155,7 +1145,7 @@ ParserState.prototype.parseVariableAssignmentExpression = function (instr) {
var lastInstrIndex = instr.length - 1; var lastInstrIndex = instr.length - 1;
if (varName.type === IFUNCALL) { if (varName.type === IFUNCALL) {
if (!this.tokens.isOperatorEnabled('()=')) { if (!this.tokens.isOperatorEnabled('()=')) {
throw new Error(qsTranslate('error', 'Function definition is not permitted.')); throw new Error('function definition is not permitted');
} }
for (var i = 0, len = varName.value + 1; i < len; i++) { for (var i = 0, len = varName.value + 1; i < len; i++) {
var index = lastInstrIndex - i; var index = lastInstrIndex - i;
@ -1169,7 +1159,7 @@ ParserState.prototype.parseVariableAssignmentExpression = function (instr) {
continue; continue;
} }
if (varName.type !== IVAR && varName.type !== IMEMBER) { if (varName.type !== IVAR && varName.type !== IMEMBER) {
throw new Error(qsTranslate('error', 'Expected variable for assignment.')); throw new Error('expected variable for assignment');
} }
this.parseVariableAssignmentExpression(varValue); this.parseVariableAssignmentExpression(varValue);
instr.push(new Instruction(IVARNAME, varName.value)); instr.push(new Instruction(IVARNAME, varName.value));
@ -1333,21 +1323,21 @@ ParserState.prototype.parseMemberExpression = function (instr) {
if (op.value === '.') { if (op.value === '.') {
if (!this.allowMemberAccess) { if (!this.allowMemberAccess) {
throw new Error(qsTranslate('error', 'Unexpected ".": member access is not permitted')); throw new Error('unexpected ".", member access is not permitted');
} }
this.expect(TNAME); this.expect(TNAME);
instr.push(new Instruction(IMEMBER, this.current.value)); instr.push(new Instruction(IMEMBER, this.current.value));
} else if (op.value === '[') { } else if (op.value === '[') {
if (!this.tokens.isOperatorEnabled('[')) { if (!this.tokens.isOperatorEnabled('[')) {
throw new Error(qsTranslate('error', 'Unexpected "[]": arrays are disabled.')); throw new Error('unexpected "[]", arrays are disabled');
} }
this.parseExpression(instr); this.parseExpression(instr);
this.expect(TBRACKET, ']'); this.expect(TBRACKET, ']');
instr.push(binaryInstruction('[')); instr.push(binaryInstruction('['));
} else { } else {
throw new Error(qsTranslate('error', 'Unexpected symbol: %1.').arg(op.value)); throw new Error('unexpected symbol: ' + op.value);
} }
} }
}; };
@ -1624,10 +1614,10 @@ function min(array) {
function arrayMap(f, a) { function arrayMap(f, a) {
if (typeof f !== 'function') { if (typeof f !== 'function') {
throw new Error(qsTranslate('error', 'First argument to map is not a function.')); throw new Error('First argument to map is not a function');
} }
if (!Array.isArray(a)) { if (!Array.isArray(a)) {
throw new Error(qsTranslate('error', 'Second argument to map is not an array.')); throw new Error('Second argument to map is not an array');
} }
return a.map(function (x, i) { return a.map(function (x, i) {
return f(x, i); return f(x, i);
@ -1636,10 +1626,10 @@ function arrayMap(f, a) {
function arrayFold(f, init, a) { function arrayFold(f, init, a) {
if (typeof f !== 'function') { if (typeof f !== 'function') {
throw new Error(qsTranslate('error', 'First argument to fold is not a function.')); throw new Error('First argument to fold is not a function');
} }
if (!Array.isArray(a)) { if (!Array.isArray(a)) {
throw new Error(qsTranslate('error', 'Second argument to fold is not an array.')); throw new Error('Second argument to fold is not an array');
} }
return a.reduce(function (acc, x, i) { return a.reduce(function (acc, x, i) {
return f(acc, x, i); return f(acc, x, i);
@ -1648,10 +1638,10 @@ function arrayFold(f, init, a) {
function arrayFilter(f, a) { function arrayFilter(f, a) {
if (typeof f !== 'function') { if (typeof f !== 'function') {
throw new Error(qsTranslate('error', 'First argument to filter is not a function.')); throw new Error('First argument to filter is not a function');
} }
if (!Array.isArray(a)) { if (!Array.isArray(a)) {
throw new Error(qsTranslate('error', 'Second argument to filter is not an array.')); throw new Error('Second argument to filter is not an array');
} }
return a.filter(function (x, i) { return a.filter(function (x, i) {
return f(x, i); return f(x, i);
@ -1660,7 +1650,7 @@ function arrayFilter(f, a) {
function stringOrArrayIndexOf(target, s) { function stringOrArrayIndexOf(target, s) {
if (!(Array.isArray(s) || typeof s === 'string')) { if (!(Array.isArray(s) || typeof s === 'string')) {
throw new Error(qsTranslate('error', 'Second argument to indexOf is not a string or array.')); throw new Error('Second argument to indexOf is not a string or array');
} }
return s.indexOf(target); return s.indexOf(target);
@ -1668,7 +1658,7 @@ function stringOrArrayIndexOf(target, s) {
function arrayJoin(sep, a) { function arrayJoin(sep, a) {
if (!Array.isArray(a)) { if (!Array.isArray(a)) {
throw new Error(qsTranslate('error', 'Second argument to join is not an array.')); throw new Error('Second argument to join is not an array');
} }
return a.join(sep); return a.join(sep);
@ -1795,7 +1785,7 @@ class Parser {
); );
parserState.parseExpression(instr); parserState.parseExpression(instr);
parserState.expect(TEOF, QT_TRANSLATE_NOOP('error','EOF')); parserState.expect(TEOF, 'EOF');
return new Expression(instr, this); return new Expression(instr, this);
} }

View file

@ -47,10 +47,6 @@ class Expression {
return this.requiredObjects().every(objName => objName in C.currentObjectsByName) return this.requiredObjects().every(objName => objName in C.currentObjectsByName)
} }
undefinedVariables() {
return this.requiredObjects().filter(objName => !(objName in C.currentObjectsByName))
}
recache() { recache() {
if(this.cached) if(this.cached)
this.cachedValue = this.calc.evaluate(C.currentObjectsByName) this.cachedValue = this.calc.evaluate(C.currentObjectsByName)