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
778fb18f
Commit
778fb18f
authored
Oct 31, 2006
by
twanvl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
made a start with script functions
parent
f8142bdd
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
372 additions
and
29 deletions
+372
-29
src/data/field.cpp
src/data/field.cpp
+2
-2
src/gui/set/window.cpp
src/gui/set/window.cpp
+7
-2
src/gui/set/window.hpp
src/gui/set/window.hpp
+2
-0
src/mse.vcproj
src/mse.vcproj
+4
-1
src/render/card/viewer.cpp
src/render/card/viewer.cpp
+3
-1
src/script/context.cpp
src/script/context.cpp
+22
-3
src/script/context.hpp
src/script/context.hpp
+2
-2
src/script/functions.cpp
src/script/functions.cpp
+258
-0
src/script/image.cpp
src/script/image.cpp
+7
-3
src/script/script.cpp
src/script/script.cpp
+1
-1
src/script/script_manager.cpp
src/script/script_manager.cpp
+4
-1
src/script/scriptable.hpp
src/script/scriptable.hpp
+1
-1
src/script/value.cpp
src/script/value.cpp
+2
-0
src/script/value.hpp
src/script/value.hpp
+30
-4
src/util/error.cpp
src/util/error.cpp
+10
-1
src/util/io/reader.cpp
src/util/io/reader.cpp
+1
-1
src/util/io/reader.hpp
src/util/io/reader.hpp
+1
-1
src/util/io/writer.cpp
src/util/io/writer.cpp
+1
-3
src/util/string.cpp
src/util/string.cpp
+10
-1
src/util/string.hpp
src/util/string.hpp
+4
-1
No files found.
src/data/field.cpp
View file @
778fb18f
...
...
@@ -76,8 +76,8 @@ shared_ptr<Field> read_new<Field>(Reader& reader) {
Style
::
Style
(
const
FieldP
&
field
)
:
fieldP
(
field
)
,
z_index
(
0
)
,
left
(
0
),
width
(
1
)
,
top
(
0
),
height
(
1
)
,
left
(
0
),
width
(
0
)
,
top
(
0
),
height
(
0
)
,
visible
(
true
)
{}
...
...
src/gui/set/window.cpp
View file @
778fb18f
...
...
@@ -546,6 +546,12 @@ void SetWindow::onChildMenu(wxCommandEvent& ev) {
current_panel
->
onCommand
(
ev
.
GetId
());
}
void
SetWindow
::
onIdle
(
wxIdleEvent
&
ev
)
{
// Stuff that must be done in the main thread
handle_pending_errors
();
// showUpdateDialog(this);
}
// ----------------------------------------------------------------------------- : Event table
BEGIN_EVENT_TABLE
(
SetWindow
,
wxFrame
)
...
...
@@ -584,7 +590,6 @@ BEGIN_EVENT_TABLE(SetWindow, wxFrame)
// EVT_FIND_REPLACE (wxID_ANY, SetWindow::onReplace)
// EVT_FIND_REPLACE_ALL(wxID_ANY, SetWindow::onReplaceAll)
EVT_CLOSE
(
SetWindow
::
onClose
)
// EVT_TIMER (wxID_ANY, SetWindow::onTick)
// EVT_IDLE ( SetWindow::onIdle)
EVT_IDLE
(
SetWindow
::
onIdle
)
EVT_CARD_SELECT
(
wxID_ANY
,
SetWindow
::
onCardSelect
)
END_EVENT_TABLE
()
src/gui/set/window.hpp
View file @
778fb18f
...
...
@@ -154,6 +154,8 @@ class SetWindow : public wxFrame, public SetView {
// --------------------------------------------------- : Window events - other
void
onChildMenu
(
wxCommandEvent
&
);
void
onIdle
(
wxIdleEvent
&
);
};
// ----------------------------------------------------------------------------- : EOF
...
...
src/mse.vcproj
View file @
778fb18f
...
...
@@ -178,7 +178,7 @@
Name=
"VCCustomBuildTool"
/>
<Tool
Name=
"VCLinkerTool"
AdditionalDependencies=
"rpcrt4.lib wsock32.lib comctl32.lib wxbase26ud.lib wxmsw26ud_core.lib wxjpegd.lib wxpngd.lib wxtiffd.lib wxzlibd.lib"
AdditionalDependencies=
"rpcrt4.lib wsock32.lib comctl32.lib wxbase26ud.lib wxmsw26ud_core.lib wxjpegd.lib wxpngd.lib wxtiffd.lib wxzlibd.lib
wxregexd.lib
"
OutputFile=
"$(OutDir)/mse.exe"
LinkIncremental=
"2"
IgnoreDefaultLibraryNames=
"libcd.lib,libcid.lib"
...
...
@@ -1131,6 +1131,9 @@
<File
RelativePath=
".\script\dependency.hpp"
>
</File>
<File
RelativePath=
".\script\functions.cpp"
>
</File>
<File
RelativePath=
".\script\image.cpp"
>
<FileConfiguration
...
...
src/render/card/viewer.cpp
View file @
778fb18f
...
...
@@ -74,7 +74,9 @@ void DataViewer::setStyles(IndexMap<FieldP,StyleP>& styles) {
// create viewers
viewers
.
clear
();
FOR_EACH
(
s
,
styles
)
{
if
(
s
->
visible
||
s
->
visible
.
isScripted
())
{
if
((
s
->
visible
||
s
->
visible
.
isScripted
())
&&
(
s
->
width
||
s
->
width
.
isScripted
())
&&
(
s
->
height
||
s
->
height
.
isScripted
()))
{
// no need to make a viewer for things that are always invisible
viewers
.
push_back
(
makeViewer
(
s
));
// REMOVEME //TODO //%%%
...
...
src/script/context.cpp
View file @
778fb18f
...
...
@@ -183,7 +183,7 @@ ScriptValueP Context::getVariable(const String& name) {
return
value
;
}
ScriptValueP
Context
::
getVariableO
rNil
(
const
String
&
name
)
{
ScriptValueP
Context
::
getVariableO
pt
(
const
String
&
name
)
{
return
variables
[
stringToVariable
(
name
)].
value
;
}
...
...
@@ -246,6 +246,25 @@ void instrUnary (UnaryInstructionType i, ScriptValueP& a) {
}
\
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
_
(
"replace_rule"
);
}
virtual
ScriptValueP
eval
(
Context
&
ctx
)
const
{
ctx
.
setVariable
(
_
(
"input"
),
a
->
eval
(
ctx
));
return
b
->
eval
(
ctx
);
}
virtual
ScriptValueP
dependencies
(
Context
&
ctx
,
const
Dependency
&
dep
)
const
{
ctx
.
setVariable
(
_
(
"input"
),
a
->
dependencies
(
ctx
,
dep
));
return
b
->
dependencies
(
ctx
,
dep
);
}
private:
ScriptValueP
a
,
b
;
};
void
instrBinary
(
BinaryInstructionType
i
,
ScriptValueP
&
a
,
const
ScriptValueP
&
b
)
{
ScriptType
at
=
a
->
type
(),
bt
=
b
->
type
();
switch
(
i
)
{
...
...
@@ -260,8 +279,8 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP&
a
=
b
;
}
else
if
(
bt
==
SCRIPT_NIL
)
{
// a = a;
//} else if (a->likesFunction() && b->likesFunction()
) {
// a = compose
(a, b);
}
else
if
(
at
==
SCRIPT_FUNCTION
&&
bt
==
SCRIPT_FUNCTION
)
{
a
=
new_intrusive2
<
ScriptCompose
>
(
a
,
b
);
}
else
if
(
at
==
SCRIPT_STRING
||
bt
==
SCRIPT_STRING
)
{
a
=
toScript
((
String
)
*
a
+
(
String
)
*
b
);
}
else
if
(
at
==
SCRIPT_DOUBLE
||
bt
==
SCRIPT_DOUBLE
)
{
...
...
src/script/context.hpp
View file @
778fb18f
...
...
@@ -54,8 +54,8 @@ class Context {
/// Get the value of a variable, throws if it not set
ScriptValueP
getVariable
(
const
String
&
name
);
/// Get the value of a variable, returns
nil
if it is not set
ScriptValueP
getVariableO
rNil
(
const
String
&
name
);
/// Get the value of a variable, returns
ScriptValue()
if it is not set
ScriptValueP
getVariableO
pt
(
const
String
&
name
);
public:
// public for FOR_EACH
/// Record of a variable
...
...
src/script/functions.cpp
0 → 100644
View file @
778fb18f
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <script/value.hpp>
#include <script/context.hpp>
#include <wx/regex.h>
DECLARE_TYPEOF_COLLECTION
(
UInt
);
/** @file script/functions.cpp
*
* @brief Functions used in scripts
*/
// ----------------------------------------------------------------------------- : Rules : regex replace
class
ScriptReplaceRule
:
public
ScriptValue
{
public:
virtual
ScriptType
type
()
const
{
return
SCRIPT_FUNCTION
;
}
virtual
String
typeName
()
const
{
return
_
(
"replace_rule"
);
}
virtual
ScriptValueP
eval
(
Context
&
ctx
)
const
{
throw
"TODO"
;
}
wxRegEx
regex
;
///< Regex to match
wxRegEx
context
;
///< Match only in a given context, optional
String
replacement
;
///< Replacement
ScriptValueP
replacement_function
;
///< Replacement function instead of a simple string, optional
};
// Create a regular expression rule for replacing in strings
SCRIPT_FUNCTION
(
replace_rule
)
{
intrusive_ptr
<
ScriptReplaceRule
>
ret
(
new
ScriptReplaceRule
);
// match
SCRIPT_PARAM
(
String
,
match
);
if
(
!
ret
->
regex
.
Compile
(
match
,
wxRE_ADVANCED
))
{
throw
ScriptError
(
_
(
"Error while compiling regular expression: '"
)
+
match
+
_
(
"'"
));
}
// replace
ScriptValueP
replace
=
ctx
.
getVariable
(
_
(
"replace"
));
if
(
replace
->
type
()
==
SCRIPT_FUNCTION
)
{
ret
->
replacement_function
=
replace
;
}
else
{
ret
->
replacement
=
(
String
)
*
replace
;
}
// in_context
SCRIPT_OPTIONAL_PARAM_N
(
String
,
"in context"
,
in_context
)
{
if
(
!
ret
->
context
.
Compile
(
in_context
,
wxRE_ADVANCED
))
{
throw
ScriptError
(
_
(
"Error while compiling regular expression: '"
)
+
in_context
+
_
(
"'"
));
}
}
return
ret
;
}
// ----------------------------------------------------------------------------- : Rules : regex filter
// ----------------------------------------------------------------------------- : Rules : sort
/// Sort a string using a specification using the shortest cycle metric, see spec_sort
String
cycle_sort
(
const
String
&
spec
,
const
String
&
input
)
{
size_t
size
=
spec
.
size
();
vector
<
UInt
>
counts
;
// count occurences of each char in spec
FOR_EACH_CONST
(
s
,
spec
)
{
UInt
c
=
0
;
FOR_EACH_CONST
(
i
,
input
)
{
if
(
s
==
i
)
c
++
;
}
counts
.
push_back
(
c
);
}
// determine best start point
size_t
best_start
=
0
;
UInt
best_start_score
=
0xffffffff
;
for
(
size_t
start
=
0
;
start
<
size
;
++
start
)
{
// score of a start position, can be considered as:
// - count saturated to binary
// - rotated left by start
// - interpreted as a binary number, but without trailing 0s
UInt
score
=
0
,
mul
=
1
;
for
(
size_t
i
=
0
;
i
<
size
;
++
i
)
{
mul
*=
2
;
if
(
counts
[(
start
+
i
)
%
size
])
{
score
=
score
*
mul
+
1
;
mul
=
1
;
}
}
if
(
score
<
best_start_score
)
{
best_start_score
=
score
;
best_start
=
start
;
}
}
// return string
String
ret
;
for
(
size_t
i
=
0
;
i
<
size
;
++
i
)
{
size_t
pos
=
(
best_start
+
i
)
%
size
;
ret
.
append
(
counts
[
pos
],
spec
[
pos
]);
}
return
ret
;
}
/// Sort a string using a sort specification
/** The specificatio can contain:
* - a = all 'a's go here
* - [abc] = 'a', 'b' and 'c' go here, in the same order as in the input
* - <abc> = 'a', 'b' and 'c' go here in that order, and only zero or one time.
* - (abc) = 'a', 'b' and 'c' go here, in the shortest order
* consider the specified characters as a clockwise circle
* then returns the input in the order that:
* 1. takes the shortest clockwise path over this circle.
* 2. has _('holes') early, a hole means a character that is in the specification
* but not in the input
* 3. prefer the one that comes the earliest in the expression (a in this case)
*
* example:
* spec_sort("XYZ<0123456789>(WUBRG)",..) // used by magic
* "W1G") -> "1GW" // could be "W...G" or "...GW", second is shorter
* "GRBUWWUG") -> "WWUUBRGG" // no difference by rule 1,2, could be "WUBRG", "UBRGW", etc.
* // becomes _("WUBRG") by rule 3
* "WUR") -> "RWU" // by rule 1 could be "R WU" or "WU R", "RUW" has an earlier hole
*/
String
spec_sort
(
const
String
&
spec
,
const
String
&
input
)
{
String
ret
;
for
(
size_t
pos
=
0
;
pos
<
spec
.
size
()
;
++
pos
)
{
Char
c
=
spec
.
GetChar
(
pos
);
if
(
c
==
_
(
'<'
))
{
// keep only a single copy
for
(
;
pos
<
spec
.
size
()
;
++
pos
)
{
Char
c
=
spec
.
GetChar
(
pos
);
if
(
c
==
_
(
'>'
))
break
;
if
(
input
.
find_first_of
(
c
)
!=
String
::
npos
)
{
ret
+=
c
;
// input contains c
}
}
if
(
pos
==
String
::
npos
)
throw
ParseError
(
_
(
"Expected '>' in sort_rule specification"
));
}
else
if
(
c
==
_
(
'['
))
{
// in any order
size_t
end
=
spec
.
find_first_of
(
_
(
']'
));
if
(
end
==
String
::
npos
)
throw
ParseError
(
_
(
"Expected ']' in sort_rule specification"
));
FOR_EACH_CONST
(
d
,
input
)
{
size_t
in_spec
=
spec
.
find_first_of
(
d
,
pos
);
if
(
in_spec
<
end
)
{
ret
+=
d
;
// d is in the part between [ and ]
}
}
pos
=
end
;
}
else
if
(
c
==
_
(
'('
))
{
// in a cycle
size_t
end
=
spec
.
find_first_of
(
_
(
')'
));
if
(
end
==
String
::
npos
)
throw
ParseError
(
_
(
"Expected ')' in sort_rule specification"
));
ret
+=
cycle_sort
(
spec
.
substr
(
pos
,
end
-
pos
-
1
),
input
);
pos
=
end
;
}
else
{
// single char
FOR_EACH_CONST
(
d
,
input
)
{
if
(
c
==
d
)
ret
+=
c
;
}
}
}
return
ret
;
}
class
ScriptSortRule
:
public
ScriptValue
{
public:
ScriptSortRule
(
const
String
&
order
)
:
order
(
order
)
{}
virtual
ScriptType
type
()
const
{
return
SCRIPT_FUNCTION
;
}
virtual
String
typeName
()
const
{
return
_
(
"sort_rule"
);
}
virtual
ScriptValueP
eval
(
Context
&
ctx
)
const
{
SCRIPT_PARAM
(
String
,
input
);
SCRIPT_RETURN
(
spec_sort
(
order
,
input
));
}
private:
String
order
;
};
// Create a rule for spec_sorting strings
SCRIPT_FUNCTION
(
sort_rule
)
{
SCRIPT_PARAM
(
String
,
order
);
return
new_intrusive1
<
ScriptSortRule
>
(
order
);
}
// ----------------------------------------------------------------------------- : String stuff
// convert a string to upper case
SCRIPT_FUNCTION
(
to_upper
)
{
SCRIPT_PARAM
(
String
,
input
);
SCRIPT_RETURN
(
input
.
Upper
());
}
// convert a string to lower case
SCRIPT_FUNCTION
(
to_lower
)
{
SCRIPT_PARAM
(
String
,
input
);
SCRIPT_RETURN
(
input
.
Lower
());
}
// convert a string to title case
SCRIPT_FUNCTION
(
to_title
)
{
SCRIPT_PARAM
(
String
,
input
);
SCRIPT_RETURN
(
capitalize
(
input
));
}
// extract a substring
SCRIPT_FUNCTION
(
substring
)
{
SCRIPT_PARAM
(
String
,
input
);
SCRIPT_PARAM_DEFAULT
(
int
,
begin
,
0
);
SCRIPT_PARAM_DEFAULT
(
int
,
end
,
INT_MAX
);
if
(
begin
<
0
)
begin
=
0
;
if
(
end
<
0
)
end
=
0
;
if
(
begin
>=
end
||
(
size_t
)
begin
>=
input
.
size
())
{
SCRIPT_RETURN
(
wxEmptyString
);
}
else
if
((
size_t
)
end
>=
input
.
size
())
{
SCRIPT_RETURN
(
input
.
substr
(
begin
));
}
else
{
SCRIPT_RETURN
(
input
.
substr
(
begin
,
end
-
begin
));
}
}
// ----------------------------------------------------------------------------- : Vector stuff
/// position of some element in a vector
/** 1 based index, 0 if not found */
int
position_in_vector
(
const
ScriptValueP
&
of
,
const
ScriptValueP
&
in
,
const
ScriptValueP
&
order_by
)
{
return
0
;
// TODO
}
// finding positions
SCRIPT_FUNCTION
(
position_of
)
{
ScriptValueP
of
=
ctx
.
getVariable
(
_
(
"of"
));
ScriptValueP
in
=
ctx
.
getVariable
(
_
(
"in"
));
ScriptValueP
order_by
=
ctx
.
getVariableOpt
(
_
(
"order by"
));
SCRIPT_RETURN
(
position_in_vector
(
of
,
in
,
order_by
));
}
// finding sizes
SCRIPT_FUNCTION
(
number_of_items
)
{
SCRIPT_RETURN
(
ctx
.
getVariable
(
_
(
"in"
))
->
itemCount
());
}
// ----------------------------------------------------------------------------- : Initialize functions
void
init_script_functions
(
Context
&
ctx
)
{
ctx
.
setVariable
(
_
(
"replace rule"
),
script_replace_rule
);
ctx
.
setVariable
(
_
(
"sort rule"
),
script_sort_rule
);
ctx
.
setVariable
(
_
(
"to upper"
),
script_to_upper
);
ctx
.
setVariable
(
_
(
"to lower"
),
script_to_lower
);
ctx
.
setVariable
(
_
(
"to title"
),
script_to_title
);
ctx
.
setVariable
(
_
(
"substring"
),
script_substring
);
ctx
.
setVariable
(
_
(
"position"
),
script_position_of
);
ctx
.
setVariable
(
_
(
"number of items"
),
script_number_of_items
);
}
src/script/image.cpp
View file @
778fb18f
...
...
@@ -111,7 +111,7 @@ ScriptImageP ScriptableImage::generate(Context& ctx, UInt width, UInt height, Pr
ScriptImageP
ScriptableImage
::
update
(
Context
&
ctx
,
UInt
width
,
UInt
height
,
PreserveAspect
preserve_aspect
,
bool
saturate
)
{
// up to date?
if
(
!
cache
||
(
UInt
)
cache
->
image
.
GetWidth
()
!=
width
||
(
UInt
)
cache
->
image
.
GetHeight
()
=
=
height
||
!
upToDate
(
ctx
,
last_update
))
{
if
(
!
cache
||
(
UInt
)
cache
->
image
.
GetWidth
()
!=
width
||
(
UInt
)
cache
->
image
.
GetHeight
()
!
=
height
||
!
upToDate
(
ctx
,
last_update
))
{
// cache must be updated
cache
=
generate
(
ctx
,
width
,
height
,
preserve_aspect
,
saturate
);
last_update
.
update
();
...
...
@@ -120,8 +120,12 @@ ScriptImageP ScriptableImage::update(Context& ctx, UInt width, UInt height, Pres
}
bool
ScriptableImage
::
upToDate
(
Context
&
ctx
,
Age
age
)
const
{
WITH_DYNAMIC_ARG
(
last_update_age
,
age
.
get
());
return
(
int
)
*
script
.
invoke
(
ctx
);
try
{
WITH_DYNAMIC_ARG
(
last_update_age
,
age
.
get
());
return
(
int
)
*
script
.
invoke
(
ctx
);
}
catch
(
Error
e
)
{
return
true
;
// script gives errors, don't update
}
}
// ----------------------------------------------------------------------------- : Reflection
...
...
src/script/script.cpp
View file @
778fb18f
...
...
@@ -41,7 +41,7 @@ String variableToString(unsigned int v) {
// ----------------------------------------------------------------------------- : Script
ScriptType
Script
::
type
()
const
{
return
SCRIPT_
SCRIPT_FU
N
;
return
SCRIPT_
FUNCTIO
N
;
}
String
Script
::
typeName
()
const
{
return
_
(
"function"
);
...
...
src/script/script_manager.cpp
View file @
778fb18f
...
...
@@ -19,6 +19,9 @@ DECLARE_TYPEOF(Contexts);
DECLARE_TYPEOF_COLLECTION
(
FieldP
);
DECLARE_TYPEOF_NO_REV
(
IndexMap_FieldP_StyleP
);
// initialize functions, from functions.cpp
void
init_script_functions
(
Context
&
ctx
);
// ----------------------------------------------------------------------------- : ScriptManager : initialization
ScriptManager
::
ScriptManager
(
Set
&
set
)
...
...
@@ -48,10 +51,10 @@ Context& ScriptManager::getContext(const StyleSheetP& stylesheet) {
// variables
// NOTE: do not use a smart pointer for the pointer to the set, because the set owns this
// which would lead to a reference cycle.
init_script_functions
(
*
ctx
);
ctx
->
setVariable
(
_
(
"set"
),
new_intrusive1
<
ScriptObject
<
Set
*>
>
(
&
set
));
ctx
->
setVariable
(
_
(
"game"
),
toScript
(
set
.
game
));
ctx
->
setVariable
(
_
(
"stylesheet"
),
toScript
(
stylesheet
));
//ctx->style->object = style;
//ctx->setVariable(_("styling"), toScript(set->extraStyleData(style)));
try
{
// perform init scripts
...
...
src/script/scriptable.hpp
View file @
778fb18f
...
...
@@ -81,7 +81,7 @@ class Scriptable {
inline
operator
const
T
&
()
const
{
return
value
;
}
inline
bool
isScripted
()
const
{
return
script
;
}
// Updates the value by executing the script, returns true if the value has changed
//
/
Updates the value by executing the script, returns true if the value has changed
inline
bool
update
(
Context
&
ctx
)
{
return
script
.
invokeOn
(
ctx
,
value
);
}
...
...
src/script/value.cpp
View file @
778fb18f
...
...
@@ -23,6 +23,7 @@ ScriptValueP ScriptValue::getMember(const String& name) const
{
throw
(
typeName
()
+
_
(
" has no member '"
)
+
name
+
_
(
"'"
));
}
ScriptValueP
ScriptValue
::
next
()
{
throw
InternalError
(
_
(
"Can't convert from "
)
+
typeName
()
+
_
(
" to iterator"
));
}
ScriptValueP
ScriptValue
::
makeIterator
()
const
{
throw
ScriptError
(
_
(
"Can't convert from "
)
+
typeName
()
+
_
(
" to collection"
));
}
int
ScriptValue
::
itemCount
()
const
{
throw
ScriptError
(
_
(
"Can't convert from "
)
+
typeName
()
+
_
(
" to collection"
));
}
void
ScriptValue
::
signalDependent
(
Context
&
,
const
Dependency
&
,
const
String
&
name
)
{}
ScriptValueP
ScriptValue
::
dependencies
(
Context
&
,
const
Dependency
&
)
const
{
return
script_nil
;
}
...
...
@@ -167,6 +168,7 @@ class ScriptString : public ScriptValue {
throw
ScriptError
(
_
(
"Not a number: '"
)
+
value
+
_
(
"'"
));
}
}
virtual
int
itemCount
()
const
{
return
(
int
)
value
.
size
();
}
private:
String
value
;
};
...
...
src/script/value.hpp
View file @
778fb18f
...
...
@@ -36,8 +36,7 @@ enum ScriptType
,
SCRIPT_STRING
,
SCRIPT_COLOR
,
SCRIPT_IMAGE
,
SCRIPT_BUILDIN_FUN
,
SCRIPT_SCRIPT_FUN
,
SCRIPT_FUNCTION
,
SCRIPT_OBJECT
,
SCRIPT_DUMMY
};
...
...
@@ -77,6 +76,8 @@ class ScriptValue {
virtual
ScriptValueP
makeIterator
()
const
;
/// Return the next item for this iterator, or ScriptValueP() if there is no such item
virtual
ScriptValueP
next
();
/// Return the number of items in this value (assuming it is a collection)
virtual
int
itemCount
()
const
;
/// Signal that a script depends on a member of this value
virtual
void
signalDependent
(
Context
&
,
const
Dependency
&
,
const
String
&
name
);
...
...
@@ -166,6 +167,7 @@ class ScriptCollection : public ScriptValue {
virtual
ScriptValueP
makeIterator
()
const
{
return
new_intrusive1
<
ScriptCollectionIterator
<
Collection
>
>
(
value
);
}
virtual
int
itemCount
()
const
{
return
(
int
)
value
->
size
();
}
private:
/// Store a pointer to a collection, collections are only ever used for structures owned outside the script
const
Collection
*
value
;
...
...
@@ -203,6 +205,7 @@ class ScriptMap : public ScriptValue {
virtual
ScriptValueP
getMember
(
const
String
&
name
)
const
{
return
get_member
(
*
value
,
name
);
}
virtual
int
itemCount
()
const
{
return
(
int
)
value
->
size
();
}
private:
/// Store a pointer to a collection, collections are only ever used for structures owned outside the script
const
Collection
*
value
;
...
...
@@ -271,7 +274,7 @@ inline ScriptValueP toScript(const shared_ptr<T>& v) { return new_intrusive1<Scr
class
ScriptBuildin_
##
name
:
public
ScriptValue
{
\
dep
\
/* virtual */
ScriptType
type
()
const
\
{
return
SCRIPT_
BUILDIN_FUN
;
}
\
{
return
SCRIPT_
FUNCTION
;
}
\
virtual
String
typeName
()
const
\
{
return
_
(
"build in function '"
)
_
(
#
name
)
_
(
"'"
);
}
\
virtual
ScriptValueP
eval
(
Context
&
)
const
;
\
...
...
@@ -284,7 +287,7 @@ inline ScriptValueP toScript(const shared_ptr<T>& v) { return new_intrusive1<Scr
* @code
* SCRIPT_FUNCTION(my_function) {
* SCRIPT_PARAM(String, my_string_param);
* ...
* ...
my_string_param ...
* }
* @endcode
* Throws an error if the parameter is not found.
...
...
@@ -292,6 +295,29 @@ inline ScriptValueP toScript(const shared_ptr<T>& v) { return new_intrusive1<Scr
#define SCRIPT_PARAM(Type, name) \
Type
name
=
*
ctx
.
getVariable
(
_
(
#
name
))
/// Retrieve an optional parameter
/** Usage:
* @code
* SCRIPT_FUNCTION(my_function) {
* SCRIPT_OPTIONAL_PARAM(String, my_string_param) {
* ... my_string_param ...
* }
* ...
* }
* @endcode
*/
#define SCRIPT_OPTIONAL_PARAM(Type, name) SCRIPT_OPTIONAL_PARAM_N(Type, name, #name)
#define SCRIPT_OPTIONAL_PARAM_N(Type, str, name) \
ScriptValueP
name
##
_
=
ctx
.
getVariableOpt
(
_
(
str
));
\
Type
name
=
name
##
_
?
*
name
##
_
:
Type
();
\
if
(
name
##
_
)
/// Retrieve an optional parameter with a default value
#define SCRIPT_PARAM_DEFAULT(Type, name, def) \
ScriptValueP
name
##
_
=
ctx
.
getVariableOpt
(
_
(
#
name
));
\
Type
name
=
name
##
_
?
*
name
##
_
:
def
/// Return a value from a SCRIPT_FUNCTION
#define SCRIPT_RETURN(value) return toScript(value)
...
...
src/util/error.cpp
View file @
778fb18f
...
...
@@ -37,7 +37,8 @@ void handle_error(const String& e, bool allow_duplicate = true, bool now = true)
}
// Only show errors in the main thread
if
(
!
now
||
!
wxThread
::
IsMain
())
{
pending_error
=
e
;
if
(
!
pending_error
.
empty
())
pending_error
+=
_
(
"
\n\n
"
);
pending_error
+=
e
;
return
;
}
// show message
...
...
@@ -47,3 +48,11 @@ void handle_error(const String& e, bool allow_duplicate = true, bool now = true)
void
handle_error
(
const
Error
&
e
,
bool
allow_duplicate
,
bool
now
)
{
handle_error
(
e
.
what
(),
allow_duplicate
,
now
);
}
void
handle_pending_errors
()
{
assert
(
wxThread
::
IsMain
());
if
(
!
pending_error
.
empty
())
{
handle_error
(
pending_error
);
pending_error
.
clear
();
}
}
src/util/io/reader.cpp
View file @
778fb18f
...
...
@@ -65,7 +65,7 @@ void Reader::showWarnings() {
bool
Reader
::
enterBlock
(
const
Char
*
name
)
{
if
(
just_opened
)
moveNext
();
// on the key of the parent block, first move inside it
if
(
indent
!=
expected_indent
)
return
false
;
// not enough indentation
if
(
name
==
key
)
{
if
(
cannocial_name_compare
(
key
,
name
)
)
{
just_opened
=
true
;
expected_indent
+=
1
;
// the indent inside the block must be at least this much
return
true
;
...
...
src/util/io/reader.hpp
View file @
778fb18f
...
...
@@ -134,7 +134,7 @@ class Reader {
/** Maybe the key is "include file" */
template
<
typename
T
>
void
unknownKey
(
T
&
v
)
{
if
(
key
==
_
(
"include
_
file"
))
{
if
(
key
==
_
(
"include
file"
))
{
Reader
reader
(
value
);
reader
.
handle
(
v
);
moveNext
();
...
...
src/util/io/writer.cpp
View file @
778fb18f
...
...
@@ -35,7 +35,7 @@ void Writer::enterBlock(const Char* name) {
}
// don't write the key yet
indentation
+=
1
;
opened_key
=
name
;
opened_key
=
cannocial_name_form
(
name
)
;
just_opened
=
true
;
}
...
...
@@ -47,8 +47,6 @@ void Writer::exitBlock() {
void
Writer
::
writeKey
()
{
writeIndentation
();
// Use ' ' instead of '_' because it is more human readable
FOR_EACH
(
c
,
opened_key
)
if
(
c
==
_
(
'_'
))
c
=
_
(
' '
);
writeUTF8
(
stream
,
opened_key
);
}
void
Writer
::
writeIndentation
()
{
...
...
src/util/string.cpp
View file @
778fb18f
...
...
@@ -123,7 +123,7 @@ String cannocial_name_form(const String& str) {
bool
leading
=
true
;
FOR_EACH_CONST
(
c
,
str
)
{
if
((
c
==
_
(
'_'
)
||
c
==
_
(
' '
))
&&
!
leading
)
{
ret
+=
_
(
'
_
'
);
ret
+=
_
(
'
'
);
}
else
if
(
isAlnum
(
c
))
{
ret
+=
toLower
(
c
);
leading
=
false
;
...
...
@@ -195,3 +195,12 @@ bool is_substr(const String& str, size_t pos, const Char* cmp) {
}
return
*
cmp
==
_
(
'\0'
);
}
bool
cannocial_name_compare
(
const
String
&
as
,
const
Char
*
b
)
{
const
Char
*
a
=
as
.
c_str
();
while
(
true
)
{
if
(
*
a
!=
*
b
&&
!
(
*
a
==
_
(
' '
)
&&
*
b
==
_
(
'_'
)))
return
false
;
if
(
*
a
==
_
(
'\0'
))
return
true
;
a
++
;
b
++
;
}
}
src/util/string.hpp
View file @
778fb18f
...
...
@@ -100,7 +100,7 @@ String capitalize(const String&);
String
capitalize_sentence
(
const
String
&
);
/// Convert a field name to cannocial form
/** - lower case and '
_' instead of '
'.
/** - lower case and '
' instead of '_
'.
* - non alphanumeric characters are droped
* - "camalCase" is converted to words "camel case" (TODO)
*/
...
...
@@ -127,5 +127,8 @@ bool starts_with(const String& str, const String& start);
/// Return whether str contains the string cmp at position pos
bool
is_substr
(
const
String
&
str
,
size_t
pos
,
const
Char
*
cmp
);
/// Compare two strings for equality, b may contain '_' where a contains ' '
bool
cannocial_name_compare
(
const
String
&
a
,
const
Char
*
b
);
// ----------------------------------------------------------------------------- : EOF
#endif
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