Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
magicseteditor
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
magicseteditor
Commits
a72371df
Commit
a72371df
authored
Jun 03, 2008
by
twanvl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Closure operator now behaves as default argument operator, documentation.
parent
d1afd16c
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
182 additions
and
60 deletions
+182
-60
doc/script/index.txt
doc/script/index.txt
+38
-0
doc/script/variables.txt
doc/script/variables.txt
+13
-0
src/data/action/keyword.cpp
src/data/action/keyword.cpp
+4
-4
src/script/context.cpp
src/script/context.cpp
+77
-24
src/script/context.hpp
src/script/context.hpp
+9
-1
src/script/dependency.cpp
src/script/dependency.cpp
+2
-2
src/script/parser.cpp
src/script/parser.cpp
+29
-25
src/util/error.cpp
src/util/error.cpp
+4
-0
src/util/error.hpp
src/util/error.hpp
+1
-0
tools/website/drupal/mse-drupal-modules/autoformat.inc
tools/website/drupal/mse-drupal-modules/autoformat.inc
+3
-2
tools/website/drupal/mse-drupal-modules/highlight.inc
tools/website/drupal/mse-drupal-modules/highlight.inc
+2
-2
No files found.
doc/script/index.txt
View file @
a72371df
...
@@ -12,3 +12,41 @@ MSE uses a custom scripting language to add complicated behaviour to [[type:fiel
...
@@ -12,3 +12,41 @@ MSE uses a custom scripting language to add complicated behaviour to [[type:fiel
See also:
See also:
* [[type:index|Data types used]]
* [[type:index|Data types used]]
* [[fun:index|Built in functions]]
* [[fun:index|Built in functions]]
--Syntax index--
| @123@ [[type:int|A literal number]]
| @"stuff"@ [[type:string|A literal string]]
| @[a,b,c]@ [[type:list|A literal list]]
| @[a:b, c:d]@ [[type:map|A literal map]]
| @{ expr }@ [[script:variables#Functions|Function definition]]
| @fun(a:b, c:d)@ [[script:variables#Functions|Function call]]
| @fun(value)@ [[script:variables#Functions|Function call with '@input@' argument]]
| @fun@@(a:b)@ [[script:variables#Default arguments|Default arguments]]
| @a.b@ [[script:operators|Property 'b' of 'a']]
| @a[b]@ [[script:operators|Property 'value of b' of 'a']]
| @-a@ [[script:operators|Negation]]
| @a + b@ [[script:operators|Addition / concatenation]]
| @a - b@ [[script:operators|Subtraction]]
| @a * b@ [[script:operators|Multiplication]]
| @a / b@ [[script:operators|Floating point division]]
| @a div b@ [[script:operators|Integer division]]
| @a mod b@ [[script:operators|Remainder]]
| @not a@ [[type:boolean|Boolean not]]
| @a and b@ [[type:boolean|Boolean conjunction]]
| @a or b@ [[type:boolean|Boolean disjunction]]
| @a xor b@ [[type:boolean|Boolean xor]]
| @a == b@ [[script:operators|Comparison for equality]]
| @a != b@ [[script:operators|Comparison for inequality]]
| @a < b@ [[script:operators|Comparison]]
| @a > b@ [[script:operators|Comparison]]
| @a <= b@ [[script:operators|Comparison]]
| @a >= b@ [[script:operators|Comparison]]
| @a or else b@ Use @a@ unless it is an error, then use @b@ instead.
| @min(a,b,c,...)@ [[script:operators|Smallest of the values]]
| @max(a,b,c,...)@ [[script:operators|Largest of the values]]
| @rgb(r,g,b)@ [[type:color|A color value]]
| @rgba(r,g,b)@ [[type:color|A color value with transparency]]
| @if x then y@ [[script:control structures|Conditional expresion]]
| @if x then y else z@ [[script:control structures|Conditional expresion]]
| @for x in list do y@ [[script:control structures|Loop over elements in a list]]
| @for x from a to b do y@ [[script:control structures|Loop over numbers from a to b]]
doc/script/variables.txt
View file @
a72371df
...
@@ -74,4 +74,17 @@ This can be done by first making a copy, and calling that:
...
@@ -74,4 +74,17 @@ This can be done by first making a copy, and calling that:
> to_upper("xyz") == "upper case: XYZ"
> to_upper("xyz") == "upper case: XYZ"
Note that @real_to_upper@ is called without extra parameters, the @input@ variable is still set from the outer call to the new @to_upper@ itself.
Note that @real_to_upper@ is called without extra parameters, the @input@ variable is still set from the outer call to the new @to_upper@ itself.
--Default arguments--
It is possible to declare default arguments for functions using the @@@@ operator.
> function := { "argument was: " + arg }@(arg:"default")
If this function is called without the @arg@ argument, then the default value @default@ is used instead.
For example:
> function() == "argument was: default"
> function(arg: "something else") == "argument was: something else"
For determining whether the argument is set only explicit arguments count, not everything in scope, so
> arg := "something else"
> function() == "argument was: default"
Defaults are evaluated at the time the @@@@ operator is evaluated, so they can be used to simulate static scoping.
<div style="text-align:right;">next: <a href="control_structures">Control structures →</a></div>
<div style="text-align:right;">next: <a href="control_structures">Control structures →</a></div>
src/data/action/keyword.cpp
View file @
a72371df
...
@@ -177,20 +177,20 @@ void KeywordReminderTextValue::highlight(const String& code, const vector<Script
...
@@ -177,20 +177,20 @@ void KeywordReminderTextValue::highlight(const String& code, const vector<Script
}
}
bool
KeywordReminderTextValue
::
checkScript
(
const
ScriptP
&
script
)
{
bool
KeywordReminderTextValue
::
checkScript
(
const
ScriptP
&
script
)
{
Context
&
ctx
=
set
.
cards
.
empty
()
?
set
.
getContext
()
:
set
.
getContext
(
set
.
cards
.
front
());
size_t
scope
=
ctx
.
openScope
();
try
{
try
{
Context
&
ctx
=
set
.
cards
.
empty
()
?
set
.
getContext
()
:
set
.
getContext
(
set
.
cards
.
front
());
LocalScope
scope
(
ctx
);
for
(
size_t
i
=
0
;
i
<
keyword
.
parameters
.
size
()
;
++
i
)
{
for
(
size_t
i
=
0
;
i
<
keyword
.
parameters
.
size
()
;
++
i
)
{
String
param
=
String
(
_
(
"param"
))
<<
(
int
)(
i
+
1
);
String
param
=
String
(
_
(
"param"
))
<<
(
int
)(
i
+
1
);
ctx
.
setVariable
(
param
,
to_script
(
param
));
ctx
.
setVariable
(
param
,
to_script
(
param
));
}
}
script
->
eval
(
ctx
);
script
->
eval
(
ctx
);
errors
.
clear
();
errors
.
clear
();
return
true
;
}
catch
(
const
Error
&
e
)
{
}
catch
(
const
Error
&
e
)
{
errors
=
e
.
what
();
errors
=
e
.
what
();
return
false
;
}
}
ctx
.
closeScope
(
scope
);
return
errors
.
empty
();
}
}
// ----------------------------------------------------------------------------- : Changing keywords : mode
// ----------------------------------------------------------------------------- : Changing keywords : mode
...
...
src/script/context.cpp
View file @
a72371df
...
@@ -12,6 +12,8 @@
...
@@ -12,6 +12,8 @@
#include <util/error.hpp>
#include <util/error.hpp>
#include <iostream>
#include <iostream>
DECLARE_TYPEOF_COLLECTION
(
pair
<
Variable
COMMA
ScriptValueP
>
);
// ----------------------------------------------------------------------------- : Context
// ----------------------------------------------------------------------------- : Context
Context
::
Context
()
Context
::
Context
()
...
@@ -34,6 +36,10 @@ void instrQuaternary(QuaternaryInstructionType i, ScriptValueP& a, const ScriptV
...
@@ -34,6 +36,10 @@ void instrQuaternary(QuaternaryInstructionType i, ScriptValueP& a, const ScriptV
ScriptValueP
Context
::
eval
(
const
Script
&
script
,
bool
useScope
)
{
ScriptValueP
Context
::
eval
(
const
Script
&
script
,
bool
useScope
)
{
if
(
level
>
500
)
{
throw
ScriptError
(
_
(
"Stack overflow"
));
}
size_t
stack_size
=
stack
.
size
();
size_t
stack_size
=
stack
.
size
();
size_t
scope
=
useScope
?
openScope
()
:
0
;
size_t
scope
=
useScope
?
openScope
()
:
0
;
try
{
try
{
...
@@ -140,7 +146,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
...
@@ -140,7 +146,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
// Closure object
// Closure object
case
I_CLOSURE
:
{
case
I_CLOSURE
:
{
makeClosure
(
i
.
data
);
makeClosure
(
i
.
data
,
instr
);
break
;
break
;
}
}
...
@@ -221,6 +227,10 @@ ScriptValueP Context::getVariable(Variable var) {
...
@@ -221,6 +227,10 @@ ScriptValueP Context::getVariable(Variable var) {
if
(
variables
[
var
].
value
)
return
variables
[
var
].
value
;
if
(
variables
[
var
].
value
)
return
variables
[
var
].
value
;
throw
ScriptError
(
_
(
"Variable not set: "
)
+
variable_to_string
(
var
));
throw
ScriptError
(
_
(
"Variable not set: "
)
+
variable_to_string
(
var
));
}
}
int
Context
::
getVariableScope
(
Variable
var
)
{
if
(
variables
[
var
].
value
)
return
level
-
variables
[
var
].
level
;
else
return
-
1
;
}
size_t
Context
::
openScope
()
{
size_t
Context
::
openScope
()
{
...
@@ -259,6 +269,62 @@ void instrUnary (UnaryInstructionType i, ScriptValueP& a) {
...
@@ -259,6 +269,62 @@ void instrUnary (UnaryInstructionType i, ScriptValueP& a) {
}
}
}
}
// ----------------------------------------------------------------------------- : Function composition
/// Composition of two functions
class
ScriptCompose
:
public
ScriptValue
{
public:
ScriptCompose
(
ScriptValueP
a
,
ScriptValueP
b
)
:
a
(
a
),
b
(
b
)
{}
virtual
ScriptType
type
()
const
{
return
SCRIPT_FUNCTION
;
}
virtual
String
typeName
()
const
{
return
_
(
"function composition"
);
}
virtual
ScriptValueP
eval
(
Context
&
ctx
)
const
{
ctx
.
setVariable
(
SCRIPT_VAR_input
,
a
->
eval
(
ctx
));
return
b
->
eval
(
ctx
);
}
virtual
ScriptValueP
dependencies
(
Context
&
ctx
,
const
Dependency
&
dep
)
const
{
ctx
.
setVariable
(
SCRIPT_VAR_input
,
a
->
dependencies
(
ctx
,
dep
));
return
b
->
dependencies
(
ctx
,
dep
);
}
private:
ScriptValueP
a
,
b
;
};
// ----------------------------------------------------------------------------- : Closures
/// A closure around a function
class
ScriptClosure
:
public
ScriptValue
{
public:
ScriptClosure
(
ScriptValueP
fun
)
:
fun
(
fun
)
{}
/// Add a binding
void
bind
(
Variable
v
,
const
ScriptValueP
&
value
)
{
bindings
.
push_back
(
make_pair
(
v
,
value
));
}
/// Apply the bindings
void
applyBindings
(
Context
&
ctx
)
const
{
FOR_EACH_CONST
(
b
,
bindings
)
{
if
(
ctx
.
getVariableScope
(
b
.
first
)
!=
0
)
{
ctx
.
setVariable
(
b
.
first
,
b
.
second
);
}
}
}
virtual
ScriptType
type
()
const
{
return
SCRIPT_FUNCTION
;
}
virtual
String
typeName
()
const
{
return
_
(
"function closure"
);
}
virtual
ScriptValueP
eval
(
Context
&
ctx
)
const
{
applyBindings
(
ctx
);
return
fun
->
eval
(
ctx
);
}
virtual
ScriptValueP
dependencies
(
Context
&
ctx
,
const
Dependency
&
dep
)
const
{
applyBindings
(
ctx
);
return
fun
->
dependencies
(
ctx
,
dep
);
}
private:
ScriptValueP
fun
;
vector
<
pair
<
Variable
,
ScriptValueP
>
>
bindings
;
};
// ----------------------------------------------------------------------------- : Simple instructions : binary
// ----------------------------------------------------------------------------- : Simple instructions : binary
// operator on ints
// operator on ints
...
@@ -284,24 +350,6 @@ void instrUnary (UnaryInstructionType i, ScriptValueP& a) {
...
@@ -284,24 +350,6 @@ void instrUnary (UnaryInstructionType i, ScriptValueP& a) {
}
\
}
\
break
break
/// Composition of two functions
class
ScriptCompose
:
public
ScriptValue
{
public:
ScriptCompose
(
ScriptValueP
a
,
ScriptValueP
b
)
:
a
(
a
),
b
(
b
)
{}
virtual
ScriptType
type
()
const
{
return
SCRIPT_FUNCTION
;
}
virtual
String
typeName
()
const
{
return
_
(
"function composition"
);
}
virtual
ScriptValueP
eval
(
Context
&
ctx
)
const
{
ctx
.
setVariable
(
SCRIPT_VAR_input
,
a
->
eval
(
ctx
));
return
b
->
eval
(
ctx
);
}
virtual
ScriptValueP
dependencies
(
Context
&
ctx
,
const
Dependency
&
dep
)
const
{
ctx
.
setVariable
(
SCRIPT_VAR_input
,
a
->
dependencies
(
ctx
,
dep
));
return
b
->
dependencies
(
ctx
,
dep
);
}
private:
ScriptValueP
a
,
b
;
};
void
instrBinary
(
BinaryInstructionType
i
,
ScriptValueP
&
a
,
const
ScriptValueP
&
b
)
{
void
instrBinary
(
BinaryInstructionType
i
,
ScriptValueP
&
a
,
const
ScriptValueP
&
b
)
{
switch
(
i
)
{
switch
(
i
)
{
...
@@ -408,9 +456,14 @@ void Context::makeObject(size_t n) {
...
@@ -408,9 +456,14 @@ void Context::makeObject(size_t n) {
stack
.
push_back
(
ret
);
stack
.
push_back
(
ret
);
}
}
void
Context
::
makeClosure
(
size_t
n
)
{
void
Context
::
makeClosure
(
size_t
n
,
const
Instruction
*&
instr
)
{
//intrusive_ptr<ScriptClosure> ret(new ScriptClosure());
intrusive_ptr
<
ScriptClosure
>
closure
(
new
ScriptClosure
(
stack
[
stack
.
size
()
-
n
-
1
]));
// TODO
for
(
size_t
j
=
0
;
j
<
n
;
++
j
)
{
//stack.push_back(ret);
closure
->
bind
((
Variable
)
instr
[
n
-
j
-
1
].
data
,
stack
.
back
());
throw
InternalError
(
_
(
"TODO: makeClosure"
));
stack
.
pop_back
();
}
// skip arguments
instr
+=
n
;
// set value
stack
.
back
()
=
closure
;
}
}
src/script/context.hpp
View file @
a72371df
...
@@ -62,12 +62,20 @@ class Context {
...
@@ -62,12 +62,20 @@ class Context {
ScriptValueP
getVariable
(
Variable
var
);
ScriptValueP
getVariable
(
Variable
var
);
/// Get the value of a variable, returns ScriptValue() if it is not set
/// Get the value of a variable, returns ScriptValue() if it is not set
inline
ScriptValueP
getVariableOpt
(
Variable
var
)
{
return
variables
[
var
].
value
;
}
inline
ScriptValueP
getVariableOpt
(
Variable
var
)
{
return
variables
[
var
].
value
;
}
/// In what scope was the variable set?
/** Returns 0 for the current scope and >0 for outer scopes.
* Returns -1 if the varible is not set
*/
int
getVariableScope
(
Variable
var
);
private:
/// Open a new scope
/// Open a new scope
/** returns the number of shadowed binding before that scope */
/** returns the number of shadowed binding before that scope */
size_t
openScope
();
size_t
openScope
();
/// Close a scope, must be passed a value from openScope
/// Close a scope, must be passed a value from openScope
void
closeScope
(
size_t
scope
);
void
closeScope
(
size_t
scope
);
friend
class
LocalScope
;
public:
// public for FOR_EACH
public:
// public for FOR_EACH
/// Record of a variable
/// Record of a variable
...
@@ -102,7 +110,7 @@ class Context {
...
@@ -102,7 +110,7 @@ class Context {
/// Make an object with n elements, popping 2n values from the stack, and push it onto the stack
/// Make an object with n elements, popping 2n values from the stack, and push it onto the stack
void
makeObject
(
size_t
n
);
void
makeObject
(
size_t
n
);
/// Make a closure with n arguments
/// Make a closure with n arguments
void
makeClosure
(
size_t
n
);
void
makeClosure
(
size_t
n
,
const
Instruction
*&
instr
);
};
};
/// A class that creates a local scope
/// A class that creates a local scope
...
...
src/script/dependency.cpp
View file @
a72371df
...
@@ -250,9 +250,9 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
...
@@ -250,9 +250,9 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
break
;
break
;
}
}
// Closure object
// Closure object
(as normal)
case
I_CLOSURE
:
{
case
I_CLOSURE
:
{
makeClosure
(
i
.
data
);
makeClosure
(
i
.
data
,
instr
);
break
;
break
;
}
}
...
...
src/script/parser.cpp
View file @
a72371df
...
@@ -104,8 +104,8 @@ class TokenIterator {
...
@@ -104,8 +104,8 @@ class TokenIterator {
vector
<
ScriptParseError
>&
errors
;
vector
<
ScriptParseError
>&
errors
;
/// Add an error message
/// Add an error message
void
add_error
(
const
String
&
message
);
void
add_error
(
const
String
&
message
);
/// Expected some token instead of what was found
/// Expected some token instead of what was found
, possibly a matching opening bracket is known
void
expected
(
const
String
&
exp
);
void
expected
(
const
String
&
exp
,
const
Token
*
opening
=
nullptr
);
};
};
// ----------------------------------------------------------------------------- : Characters
// ----------------------------------------------------------------------------- : Characters
...
@@ -293,25 +293,28 @@ void TokenIterator::readStringToken() {
...
@@ -293,25 +293,28 @@ void TokenIterator::readStringToken() {
}
}
}
}
int
line_number
(
size_t
pos
,
const
String
&
input
)
{
void
TokenIterator
::
add_error
(
const
String
&
message
)
{
if
(
!
errors
.
empty
()
&&
errors
.
back
().
start
==
pos
)
return
;
// already an error here
// find line number
int
line
=
1
;
int
line
=
1
;
for
(
size_t
i
=
0
;
i
<
input
.
size
()
&&
i
<
pos
;
++
i
)
{
for
(
size_t
i
=
0
;
i
<
input
.
size
()
&&
i
<
pos
;
++
i
)
{
if
(
input
.
GetChar
(
i
)
==
_
(
'\n'
))
line
++
;
if
(
input
.
GetChar
(
i
)
==
_
(
'\n'
))
line
++
;
}
}
errors
.
push_back
(
ScriptParseError
(
pos
,
line
,
filename
,
message
));
return
line
;
}
void
TokenIterator
::
add_error
(
const
String
&
message
)
{
if
(
!
errors
.
empty
()
&&
errors
.
back
().
start
==
pos
)
return
;
// already an error here
// add error message
errors
.
push_back
(
ScriptParseError
(
pos
,
line_number
(
pos
,
input
),
filename
,
message
));
}
}
void
TokenIterator
::
expected
(
const
String
&
expected
)
{
void
TokenIterator
::
expected
(
const
String
&
expected
,
const
Token
*
opening
)
{
size_t
error_pos
=
peek
(
0
).
pos
;
size_t
error_pos
=
peek
(
0
).
pos
;
if
(
!
errors
.
empty
()
&&
errors
.
back
().
start
==
pos
)
return
;
// already an error here
if
(
!
errors
.
empty
()
&&
errors
.
back
().
start
==
pos
)
return
;
// already an error here
// find line number
// add error message
int
line
=
1
;
if
(
opening
)
{
for
(
size_t
i
=
0
;
i
<
input
.
size
()
&&
i
<
error_pos
;
++
i
)
{
errors
.
push_back
(
ScriptParseError
(
opening
->
pos
,
error_pos
,
line_number
(
opening
->
pos
,
input
),
filename
,
opening
->
value
,
expected
,
peek
(
0
).
value
));
if
(
input
.
GetChar
(
i
)
==
_
(
'\n'
))
line
++
;
}
else
{
errors
.
push_back
(
ScriptParseError
(
error_pos
,
line_number
(
error_pos
,
input
),
filename
,
expected
,
peek
(
0
).
value
));
}
}
errors
.
push_back
(
ScriptParseError
(
error_pos
,
line
,
filename
,
expected
,
peek
(
0
).
value
));
}
}
...
@@ -385,12 +388,12 @@ ScriptP parse(const String& s, Packaged* package, bool string_mode) {
...
@@ -385,12 +388,12 @@ ScriptP parse(const String& s, Packaged* package, bool string_mode) {
// Expect a token, adds an error if it is not found
// Expect a token, adds an error if it is not found
bool
expectToken
(
TokenIterator
&
input
,
const
Char
*
expect
,
const
Char
*
name_in_error
=
nullptr
)
{
bool
expectToken
(
TokenIterator
&
input
,
const
Char
*
expect
,
const
Token
*
opening
=
nullptr
,
const
Char
*
name_in_error
=
nullptr
)
{
Token
token
=
input
.
read
();
Token
token
=
input
.
read
();
if
(
token
==
expect
)
{
if
(
token
==
expect
)
{
return
true
;
return
true
;
}
else
{
}
else
{
input
.
expected
(
name_in_error
?
name_in_error
:
expect
);
input
.
expected
(
name_in_error
?
name_in_error
:
expect
,
opening
);
return
false
;
return
false
;
}
}
}
}
...
@@ -398,16 +401,16 @@ bool expectToken(TokenIterator& input, const Char* expect, const Char* name_in_e
...
@@ -398,16 +401,16 @@ bool expectToken(TokenIterator& input, const Char* expect, const Char* name_in_e
void
parseExpr
(
TokenIterator
&
input
,
Script
&
script
,
Precedence
minPrec
)
{
void
parseExpr
(
TokenIterator
&
input
,
Script
&
script
,
Precedence
minPrec
)
{
// usually loop only once, unless we encounter newlines
// usually loop only once, unless we encounter newlines
while
(
true
)
{
while
(
true
)
{
const
Token
&
token
=
input
.
read
();
Token
token
=
input
.
read
();
if
(
token
==
_
(
"("
))
{
if
(
token
==
_
(
"("
))
{
// Parentheses = grouping for precedence of expressions
// Parentheses = grouping for precedence of expressions
parseOper
(
input
,
script
,
PREC_ALL
);
parseOper
(
input
,
script
,
PREC_ALL
);
expectToken
(
input
,
_
(
")"
));
expectToken
(
input
,
_
(
")"
)
,
&
token
);
}
else
if
(
token
==
_
(
"{"
))
{
}
else
if
(
token
==
_
(
"{"
))
{
// {} = function block. Parse a new Script
// {} = function block. Parse a new Script
intrusive_ptr
<
Script
>
subScript
(
new
Script
);
intrusive_ptr
<
Script
>
subScript
(
new
Script
);
parseOper
(
input
,
*
subScript
,
PREC_ALL
);
parseOper
(
input
,
*
subScript
,
PREC_ALL
);
expectToken
(
input
,
_
(
"}"
));
expectToken
(
input
,
_
(
"}"
)
,
&
token
);
script
.
addInstruction
(
I_PUSH_CONST
,
subScript
);
script
.
addInstruction
(
I_PUSH_CONST
,
subScript
);
}
else
if
(
token
==
_
(
"["
))
{
}
else
if
(
token
==
_
(
"["
))
{
// [] = list or map literal
// [] = list or map literal
...
@@ -432,7 +435,7 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
...
@@ -432,7 +435,7 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
t
=
input
.
peek
();
t
=
input
.
peek
();
}
}
}
}
expectToken
(
input
,
_
(
"]"
));
expectToken
(
input
,
_
(
"]"
)
,
&
token
);
script
.
addInstruction
(
I_MAKE_OBJECT
,
count
);
script
.
addInstruction
(
I_MAKE_OBJECT
,
count
);
}
else
if
(
minPrec
<=
PREC_UNARY
&&
token
==
_
(
"-"
))
{
}
else
if
(
minPrec
<=
PREC_UNARY
&&
token
==
_
(
"-"
))
{
parseOper
(
input
,
script
,
PREC_UNARY
,
I_UNARY
,
I_NEGATE
);
// unary negation
parseOper
(
input
,
script
,
PREC_UNARY
,
I_UNARY
,
I_NEGATE
);
// unary negation
...
@@ -538,7 +541,7 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
...
@@ -538,7 +541,7 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
parseOper
(
input
,
script
,
PREC_ALL
);
// second, third, etc.
parseOper
(
input
,
script
,
PREC_ALL
);
// second, third, etc.
script
.
addInstruction
(
I_BINARY
,
op
);
script
.
addInstruction
(
I_BINARY
,
op
);
}
}
expectToken
(
input
,
_
(
")"
));
expectToken
(
input
,
_
(
")"
)
,
&
token
);
}
else
{
}
else
{
// variable
// variable
Variable
var
=
string_to_variable
(
token
.
value
);
Variable
var
=
string_to_variable
(
token
.
value
);
...
@@ -572,7 +575,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
...
@@ -572,7 +575,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
// EBNF: expr = expr | expr oper expr
// EBNF: expr = expr | expr oper expr
// without left recursion: expr = expr (oper expr)*
// without left recursion: expr = expr (oper expr)*
while
(
true
)
{
while
(
true
)
{
const
Token
&
token
=
input
.
read
();
Token
token
=
input
.
read
();
if
(
token
!=
TOK_OPER
&&
token
!=
TOK_NAME
&&
token
!=
TOK_LPAREN
&&
if
(
token
!=
TOK_OPER
&&
token
!=
TOK_NAME
&&
token
!=
TOK_LPAREN
&&
!
((
token
==
TOK_STRING
||
token
==
TOK_INT
||
token
==
TOK_DOUBLE
)
&&
minPrec
<=
PREC_NEWLINE
&&
token
.
newline
))
{
!
((
token
==
TOK_STRING
||
token
==
TOK_INT
||
token
==
TOK_DOUBLE
)
&&
minPrec
<=
PREC_NEWLINE
&&
token
.
newline
))
{
// not an operator-like token
// not an operator-like token
...
@@ -646,11 +649,12 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
...
@@ -646,11 +649,12 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
}
else
{
}
else
{
script
.
addInstruction
(
I_BINARY
,
I_MEMBER
);
script
.
addInstruction
(
I_BINARY
,
I_MEMBER
);
}
}
expectToken
(
input
,
_
(
"]"
));
expectToken
(
input
,
_
(
"]"
)
,
&
token
);
}
else
if
(
minPrec
<=
PREC_FUN
&&
token
==
_
(
"("
))
{
}
else
if
(
minPrec
<=
PREC_FUN
&&
token
==
_
(
"("
))
{
// function call, read arguments
// function call, read arguments
vector
<
Variable
>
arguments
;
vector
<
Variable
>
arguments
;
parseCallArguments
(
input
,
script
,
arguments
);
parseCallArguments
(
input
,
script
,
arguments
);
expectToken
(
input
,
_
(
")"
),
&
token
);
// generate instruction
// generate instruction
script
.
addInstruction
(
I_CALL
,
(
unsigned
int
)
arguments
.
size
());
script
.
addInstruction
(
I_CALL
,
(
unsigned
int
)
arguments
.
size
());
FOR_EACH
(
arg
,
arguments
)
{
FOR_EACH
(
arg
,
arguments
)
{
...
@@ -658,9 +662,10 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
...
@@ -658,9 +662,10 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
}
}
}
else
if
(
minPrec
<=
PREC_FUN
&&
token
==
_
(
"@"
))
{
}
else
if
(
minPrec
<=
PREC_FUN
&&
token
==
_
(
"@"
))
{
// closure call, read arguments
// closure call, read arguments
expectToken
(
input
,
_
(
"("
));
vector
<
Variable
>
arguments
;
vector
<
Variable
>
arguments
;
expectToken
(
input
,
_
(
"("
));
parseCallArguments
(
input
,
script
,
arguments
);
parseCallArguments
(
input
,
script
,
arguments
);
expectToken
(
input
,
_
(
")"
),
&
token
);
// generate instruction
// generate instruction
script
.
addInstruction
(
I_CLOSURE
,
(
unsigned
int
)
arguments
.
size
());
script
.
addInstruction
(
I_CLOSURE
,
(
unsigned
int
)
arguments
.
size
());
FOR_EACH
(
arg
,
arguments
)
{
FOR_EACH
(
arg
,
arguments
)
{
...
@@ -676,7 +681,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
...
@@ -676,7 +681,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
}
else
{
}
else
{
parseOper
(
input
,
script
,
PREC_ALL
,
I_BINARY
,
I_ADD
);
// e
parseOper
(
input
,
script
,
PREC_ALL
,
I_BINARY
,
I_ADD
);
// e
}
}
if
(
expectToken
(
input
,
_
(
"}
\"
"
),
_
(
"}"
)))
{
if
(
expectToken
(
input
,
_
(
"}
\"
"
),
&
token
,
_
(
"}"
)))
{
parseOper
(
input
,
script
,
PREC_NONE
);
// y
parseOper
(
input
,
script
,
PREC_NONE
);
// y
// optimize: e + "" -> e
// optimize: e + "" -> e
i
=
script
.
getInstructions
().
back
();
i
=
script
.
getInstructions
().
back
();
...
@@ -724,5 +729,4 @@ void parseCallArguments(TokenIterator& input, Script& script, vector<Variable>&
...
@@ -724,5 +729,4 @@ void parseCallArguments(TokenIterator& input, Script& script, vector<Variable>&
t
=
input
.
peek
();
t
=
input
.
peek
();
}
}
}
}
expectToken
(
input
,
_
(
")"
));
}
}
src/util/error.cpp
View file @
a72371df
...
@@ -33,6 +33,10 @@ ScriptParseError::ScriptParseError(size_t pos, int line, const String& filename,
...
@@ -33,6 +33,10 @@ ScriptParseError::ScriptParseError(size_t pos, int line, const String& filename,
:
ParseError
(
_
(
"Expected '"
)
+
exp
+
_
(
"' instead of '"
)
+
found
+
_
(
"'"
))
:
ParseError
(
_
(
"Expected '"
)
+
exp
+
_
(
"' instead of '"
)
+
found
+
_
(
"'"
))
,
start
(
pos
),
end
(
pos
+
found
.
size
()),
line
(
line
),
filename
(
filename
)
,
start
(
pos
),
end
(
pos
+
found
.
size
()),
line
(
line
),
filename
(
filename
)
{}
{}
ScriptParseError
::
ScriptParseError
(
size_t
pos1
,
size_t
pos2
,
int
line
,
const
String
&
filename
,
const
String
&
open
,
const
String
&
close
,
const
String
&
found
)
:
ParseError
(
_
(
"Expected closing '"
)
+
close
+
_
(
"' for this '"
)
+
open
+
_
(
"' instead of '"
)
+
found
+
_
(
"'"
))
,
start
(
pos1
),
end
(
pos2
+
found
.
size
()),
line
(
line
),
filename
(
filename
)
{}
String
ScriptParseError
::
what
()
const
{
String
ScriptParseError
::
what
()
const
{
return
String
(
_
(
"("
))
<<
(
int
)
start
<<
_
(
"): "
)
<<
Error
::
what
();
return
String
(
_
(
"("
))
<<
(
int
)
start
<<
_
(
"): "
)
<<
Error
::
what
();
}
}
...
...
src/util/error.hpp
View file @
a72371df
...
@@ -83,6 +83,7 @@ class ScriptParseError : public ParseError {
...
@@ -83,6 +83,7 @@ class ScriptParseError : public ParseError {
public:
public:
ScriptParseError
(
size_t
pos
,
int
line
,
const
String
&
filename
,
const
String
&
str
);
ScriptParseError
(
size_t
pos
,
int
line
,
const
String
&
filename
,
const
String
&
str
);
ScriptParseError
(
size_t
pos
,
int
line
,
const
String
&
filename
,
const
String
&
expected
,
const
String
&
found
);
ScriptParseError
(
size_t
pos
,
int
line
,
const
String
&
filename
,
const
String
&
expected
,
const
String
&
found
);
ScriptParseError
(
size_t
pos1
,
size_t
pos2
,
int
line
,
const
String
&
filename
,
const
String
&
open
,
const
String
&
close
,
const
String
&
found
);
/// Position of the error
/// Position of the error
size_t
start
,
end
;
size_t
start
,
end
;
/// Line number of the error (the first line is 1)
/// Line number of the error (the first line is 1)
...
...
tools/website/drupal/mse-drupal-modules/autoformat.inc
View file @
a72371df
...
@@ -256,14 +256,15 @@ function autoformat__table($rows) {
...
@@ -256,14 +256,15 @@ function autoformat__table($rows) {
function
autoformat__line
(
$line
)
{
function
autoformat__line
(
$line
)
{
$line
=
preg_replace
(
"/'''(.*?)'''/"
,
"<strong>
\\
1</strong>"
,
$line
);
$line
=
preg_replace
(
"/'''(.*?)'''/"
,
"<strong>
\\
1</strong>"
,
$line
);
$line
=
preg_replace
(
"/''(.*?)''/"
,
"<em>
\\
1</em>"
,
$line
);
$line
=
preg_replace
(
"/''(.*?)''/"
,
"<em>
\\
1</em>"
,
$line
);
$line
=
preg_replace_callback
(
"/@(
.*?
)@/"
,
"autoformat__code"
,
$line
);
$line
=
preg_replace_callback
(
"/@(
([^@]|@@)*
)@/"
,
"autoformat__code"
,
$line
);
$line
=
preg_replace_callback
(
"/\[\[(.*?)\|(.*?)]]/"
,
"autoformat__link_s"
,
$line
);
$line
=
preg_replace_callback
(
"/\[\[(.*?)\|(.*?)]]/"
,
"autoformat__link_s"
,
$line
);
$line
=
preg_replace_callback
(
"/\[\[(.*?)]](s?)/"
,
"autoformat__link"
,
$line
);
$line
=
preg_replace_callback
(
"/\[\[(.*?)]](s?)/"
,
"autoformat__link"
,
$line
);
return
$line
;
return
$line
;
}
}
function
autoformat__code
(
$matches
)
{
function
autoformat__code
(
$matches
)
{
return
'<tt>'
.
syntax_highlight
(
htmlspecialchars
(
$matches
[
1
]))
.
'</tt>'
;
$code
=
str_replace
(
'@@'
,
'@'
,
$matches
[
1
]);
return
'<tt>'
.
syntax_highlight
(
htmlspecialchars
(
$code
))
.
'</tt>'
;
}
}
function
autoformat__link
(
$matches
)
{
function
autoformat__link
(
$matches
)
{
...
...
tools/website/drupal/mse-drupal-modules/highlight.inc
View file @
a72371df
...
@@ -131,7 +131,7 @@ function highlight_script($code) {
...
@@ -131,7 +131,7 @@ function highlight_script($code) {
while
(
strlen
(
$code
))
{
while
(
strlen
(
$code
))
{
if
(
preg_match
(
"@^<[^>]+>@"
,
$code
,
$matches
))
{
if
(
preg_match
(
"@^<[^>]+>@"
,
$code
,
$matches
))
{
$ret
.=
$matches
[
0
];
// plain tag
$ret
.=
$matches
[
0
];
// plain tag
}
else
if
(
preg_match
(
"@^(if|then|else|for( each)?|in(?= )|do|div|mod|and|or|xor|not|rgb|rgba|from|to)\b(?!:)@"
,
$code
,
$matches
))
{
}
else
if
(
preg_match
(
"@^(if|then|else|for( each)?|in(?= )|do|div|mod|and|or|xor|not|rgb|rgba|from|to
|min|max
)\b(?!:)@"
,
$code
,
$matches
))
{
$ret
.=
"<span class='hl-kw'>"
.
$matches
[
0
]
.
"</span>"
;
$ret
.=
"<span class='hl-kw'>"
.
$matches
[
0
]
.
"</span>"
;
}
else
if
(
preg_match
(
"@^(include file:)(.*)@"
,
$code
,
$matches
))
{
}
else
if
(
preg_match
(
"@^(include file:)(.*)@"
,
$code
,
$matches
))
{
$ret
.=
"<span class='hl-key'>"
.
$matches
[
1
]
.
"</span>"
.
$matches
[
2
];
$ret
.=
"<span class='hl-key'>"
.
$matches
[
1
]
.
"</span>"
.
$matches
[
2
];
...
@@ -150,7 +150,7 @@ function highlight_script($code) {
...
@@ -150,7 +150,7 @@ function highlight_script($code) {
if
(
$matches
[
2
]
==
'{'
)
$string
.=
's'
;
if
(
$matches
[
2
]
==
'{'
)
$string
.=
's'
;
}
else
if
(
preg_match
(
"@^
\\
#.*@"
,
$code
,
$matches
))
{
}
else
if
(
preg_match
(
"@^
\\
#.*@"
,
$code
,
$matches
))
{
$ret
.=
"<span class='hl-comment'>"
.
$matches
[
0
]
.
"</span>"
;
$ret
.=
"<span class='hl-comment'>"
.
$matches
[
0
]
.
"</span>"
;
}
else
if
(
preg_match
(
"@^([-+*/=!.]|<|>)+|^:=@"
,
$code
,
$matches
))
{
}
else
if
(
preg_match
(
"@^([-+*/=!.
\@
]|<|>)+|^:=@"
,
$code
,
$matches
))
{
$ret
.=
"<span class='hl-op'>"
.
$matches
[
0
]
.
"</span>"
;
$ret
.=
"<span class='hl-op'>"
.
$matches
[
0
]
.
"</span>"
;
}
else
if
(
preg_match
(
"@^([}]|[
\\
(
\\
)
\\
[
\\
]{,]+)@"
,
$code
,
$matches
))
{
}
else
if
(
preg_match
(
"@^([}]|[
\\
(
\\
)
\\
[
\\
]{,]+)@"
,
$code
,
$matches
))
{
$ret
.=
"<span class='hl-paren'>"
.
$matches
[
0
]
.
"</span>"
;
$ret
.=
"<span class='hl-paren'>"
.
$matches
[
0
]
.
"</span>"
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment