commit
ae0158a1cd
23 changed files with 2007 additions and 29 deletions
|
|
@ -54,11 +54,18 @@ matrix:
|
||||||
language: php
|
language: php
|
||||||
php: "5.4"
|
php: "5.4"
|
||||||
env: BINDINGS=php CC=clang
|
env: BINDINGS=php CC=clang
|
||||||
|
- compiler: gcc
|
||||||
|
language: dotnet
|
||||||
|
env: BINDINGS=dotnet
|
||||||
|
- compiler: clang
|
||||||
|
language: dotnet
|
||||||
|
env: BINDINGS=dotnet CC=clang
|
||||||
before_install:
|
before_install:
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
- if [ "$BINDINGS" != "none" ]; then sudo apt-get install -qq swig; fi
|
- if [ "$BINDINGS" != "none" ]; then sudo apt-get install -qq swig; fi
|
||||||
- if [ "$BINDINGS" == "perl" ]; then sudo add-apt-repository ppa:dns/irc -y; sudo apt-get update -qq; sudo apt-get install -qq swig=2.0.8-1irc1~12.04; fi
|
- if [ "$BINDINGS" == "perl" ]; then sudo add-apt-repository ppa:dns/irc -y; sudo apt-get update -qq; sudo apt-get install -qq swig=2.0.8-1irc1~12.04; fi
|
||||||
- if [ "$BINDINGS" == "python" ]; then sudo apt-get install -qq python-dev; fi
|
- if [ "$BINDINGS" == "python" ]; then sudo apt-get install -qq python-dev; fi
|
||||||
|
- if [ "$BINDINGS" == "dotnet" ]; then sudo add-apt-repository ppa:directhex/monoxide -y; sudo apt-get update -qq; sudo apt-get install -qq mono-devel mono-mcs nunit nunit-console; mozroots --import --sync; fi
|
||||||
|
|
||||||
install: true
|
install: true
|
||||||
before_script:
|
before_script:
|
||||||
|
|
|
||||||
6
HACKING
6
HACKING
|
|
@ -59,4 +59,8 @@ There is a language-independent representation of the Hammer test
|
||||||
suite in `lib/test-suite`. This is intended to be used with the
|
suite in `lib/test-suite`. This is intended to be used with the
|
||||||
tsparser.pl prolog library, along with a language-specific frontend.
|
tsparser.pl prolog library, along with a language-specific frontend.
|
||||||
|
|
||||||
No language-specific frontends have been written yet.
|
Only the C# frontend exists so far; to regenerate the test suites using it, run
|
||||||
|
|
||||||
|
$ swipl -q -t halt -g tsgencsharp:prolog tsgencsharp.pl \
|
||||||
|
>../src/bindings/dotnet/test/hammer_tests.cs
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ Features
|
||||||
* Perl
|
* Perl
|
||||||
* [Go](https://github.com/prevoty/hammer)
|
* [Go](https://github.com/prevoty/hammer)
|
||||||
* PHP
|
* PHP
|
||||||
* .NET (not yet implemented)
|
* .NET
|
||||||
|
|
||||||
Installing
|
Installing
|
||||||
==========
|
==========
|
||||||
|
|
@ -39,8 +39,10 @@ Installing
|
||||||
* python2.7-dev (for Python bindings)
|
* python2.7-dev (for Python bindings)
|
||||||
* a JDK (for Java bindings)
|
* a JDK (for Java bindings)
|
||||||
* a working [phpenv](https://github.com/CHH/phpenv) configuration (for PHP bindings)
|
* a working [phpenv](https://github.com/CHH/phpenv) configuration (for PHP bindings)
|
||||||
|
* mono-devel and mono-mcs (>= 3.0.6) (for .NET bindings)
|
||||||
|
* nunit (for testing .NET bindings)
|
||||||
|
|
||||||
To build, type `scons`. To run the built-in test suite, type `scons test`. For a debug build, add `--variant=debug`
|
To build, type `scons`. To run the built-in test suite, type `scons test`. For a debug build, add `--variant=debug`.
|
||||||
|
|
||||||
To build bindings, pass a "bindings" argument to scons, e.g. `scons bindings=python`. `scons bindings=python test` will build Python bindings and run tests for both C and Python. `--variant=debug` is valid here too. You can build more than one set of bindings at a time; just separate them with commas, e.g. `scons bindings=python,perl`.
|
To build bindings, pass a "bindings" argument to scons, e.g. `scons bindings=python`. `scons bindings=python test` will build Python bindings and run tests for both C and Python. `--variant=debug` is valid here too. You can build more than one set of bindings at a time; just separate them with commas, e.g. `scons bindings=python,perl`.
|
||||||
|
|
||||||
|
|
@ -69,6 +71,8 @@ The Python bindings only work with Python 2.7. SCons doesn't work with Python 3,
|
||||||
|
|
||||||
The requirement for SWIG >= 2.0.8 for Perl bindings is due to a [known bug](http://sourceforge.net/p/swig/patches/324/) in SWIG. [ppa:dns/irc](https://launchpad.net/~dns/+archive/irc) has backports of SWIG 2.0.8 for Ubuntu versions 10.04-12.10; you can also [build SWIG from source](http://www.swig.org/download.html).
|
The requirement for SWIG >= 2.0.8 for Perl bindings is due to a [known bug](http://sourceforge.net/p/swig/patches/324/) in SWIG. [ppa:dns/irc](https://launchpad.net/~dns/+archive/irc) has backports of SWIG 2.0.8 for Ubuntu versions 10.04-12.10; you can also [build SWIG from source](http://www.swig.org/download.html).
|
||||||
|
|
||||||
|
The .NET bindings are for Mono 3.0.6 and greater. If you're on a Debian-based distro that only provides Mono 2 (e.g., Ubuntu 12.04), there are backports for [3.0.x](http://www.meebey.net/posts/mono_3.0_preview_debian_ubuntu_packages/), and a [3.2.x PPA](https://launchpad.net/~directhex/+archive/monoxide) maintained by the Mono team.
|
||||||
|
|
||||||
Community
|
Community
|
||||||
=========
|
=========
|
||||||
Please join us at `#hammer` on `irc.upstandinghackers.com` if you have any questions or just want to talk about parsing.
|
Please join us at `#hammer` on `irc.upstandinghackers.com` if you have any questions or just want to talk about parsing.
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,12 @@ import sys
|
||||||
vars = Variables(None, ARGUMENTS)
|
vars = Variables(None, ARGUMENTS)
|
||||||
vars.Add(PathVariable('DESTDIR', "Root directory to install in (useful for packaging scripts)", None, PathVariable.PathIsDirCreate))
|
vars.Add(PathVariable('DESTDIR', "Root directory to install in (useful for packaging scripts)", None, PathVariable.PathIsDirCreate))
|
||||||
vars.Add(PathVariable('prefix', "Where to install in the FHS", "/usr/local", PathVariable.PathAccept))
|
vars.Add(PathVariable('prefix', "Where to install in the FHS", "/usr/local", PathVariable.PathAccept))
|
||||||
vars.Add(ListVariable('bindings', 'Language bindings to build', 'none', ['python', 'perl', 'php']))
|
vars.Add(ListVariable('bindings', 'Language bindings to build', 'none', ['dotnet', 'perl', 'php', 'python']))
|
||||||
|
|
||||||
env = Environment(ENV = {'PATH' : os.environ['PATH']}, variables = vars, tools=['default', 'scanreplace'], toolpath=['tools'])
|
env = Environment(ENV = {'PATH' : os.environ['PATH']},
|
||||||
|
variables = vars,
|
||||||
|
tools=['default', 'scanreplace', 'csharp/mono'],
|
||||||
|
toolpath=['tools'])
|
||||||
|
|
||||||
if not 'bindings' in env:
|
if not 'bindings' in env:
|
||||||
env['bindings'] = []
|
env['bindings'] = []
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@ many1 {
|
||||||
test "daabbabadef" --> fail;
|
test "daabbabadef" --> fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
repeat-n {
|
repeat_n {
|
||||||
parser repeat_n(choice(ch('a'),ch('b')),0x2);
|
parser repeat_n(choice(ch('a'),ch('b')),0x2);
|
||||||
test "adef" --> fail;
|
test "adef" --> fail;
|
||||||
test "abdef" --> ['a','b'];
|
test "abdef" --> ['a','b'];
|
||||||
|
|
@ -270,24 +270,27 @@ and {
|
||||||
}
|
}
|
||||||
|
|
||||||
not {
|
not {
|
||||||
parser sequence(ch('a'), choice(token('+'), token("++")), ch('b'));
|
parser sequence(ch('a'), choice(token("+"), token("++")), ch('b'));
|
||||||
test "a+b" --> ['a',"+",'b'];
|
test "a+b" --> ['a',"+",'b'];
|
||||||
test "a++b" --> fail;
|
test "a++b" --> fail;
|
||||||
|
|
||||||
parser sequence(ch('a'), choice(sequence(token('+'), not(ch('+'))),
|
parser sequence(ch('a'), choice(sequence(token("+"), not(ch('+'))),
|
||||||
token("++")),
|
token("++")),
|
||||||
ch('b'));
|
ch('b'));
|
||||||
test "a+b" --> ['a', ["+"], 'b'];
|
test "a+b" --> ['a', ["+"], 'b'];
|
||||||
test "a++b" --> ['a', "++", 'b'];
|
test "a++b" --> ['a', "++", 'b'];
|
||||||
}
|
}
|
||||||
|
|
||||||
leftrec {
|
## This doesn't work for some reason; it segfaults. We'll leave it for
|
||||||
subparser $lr = choice(sequence($lr, ch('a')), epsilon_p());
|
## later.
|
||||||
parser $lr;
|
#
|
||||||
test "a" --> ['a'];
|
#leftrec {
|
||||||
test "aa" --> [['a'],'a'];
|
# subparser $lr = choice(sequence($lr, ch('a')), epsilon_p());
|
||||||
test "aaa" --> [[['a'],'a'],'a'];
|
# parser $lr;
|
||||||
}
|
# test "a" --> ['a'];
|
||||||
|
# #test "aa" --> [['a'],'a'];
|
||||||
|
# #test "aaa" --> [[['a'],'a'],'a'];
|
||||||
|
#}
|
||||||
|
|
||||||
rightrec {
|
rightrec {
|
||||||
subparser $rr = choice(sequence(ch('a'), $rr), epsilon_p());
|
subparser $rr = choice(sequence(ch('a'), $rr), epsilon_p());
|
||||||
|
|
|
||||||
212
lib/tsgencsharp.pl
Normal file
212
lib/tsgencsharp.pl
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
% -*- prolog -*-
|
||||||
|
% Run with:
|
||||||
|
% $ swipl -q -t halt -g tsgencsharp:prolog tsgencsharp.pl >output-file
|
||||||
|
% Note: this needs to be run from the lib/ directory.
|
||||||
|
|
||||||
|
% So,
|
||||||
|
% swipl -q -t halt -g tsgencsharp:prolog tsgencsharp.pl >../src/bindings/dotnet/test/hammer_tests.cs
|
||||||
|
|
||||||
|
|
||||||
|
:- module(tsgencsharp,
|
||||||
|
[gen_ts/2]).
|
||||||
|
|
||||||
|
:- expects_dialect(swi).
|
||||||
|
:- use_module(tsparser).
|
||||||
|
|
||||||
|
% TODO: build a Box-like pretty-printer
|
||||||
|
|
||||||
|
format_parser_name(Name, Result) :-
|
||||||
|
atom_codes(Name, [CInit|CName]),
|
||||||
|
code_type(RInit, to_upper(CInit)),
|
||||||
|
append("Hammer.", [RInit|CName], Result), !.
|
||||||
|
|
||||||
|
format_test_name(Name, Result) :-
|
||||||
|
atom_codes(Name, [CInit|CName]),
|
||||||
|
code_type(RInit, to_upper(CInit)),
|
||||||
|
append("Test", [RInit|CName], Result), !.
|
||||||
|
|
||||||
|
indent(0) --> "", !.
|
||||||
|
indent(N) -->
|
||||||
|
{N > 0},
|
||||||
|
" ",
|
||||||
|
{Np is N - 1},
|
||||||
|
indent(Np).
|
||||||
|
|
||||||
|
pp_char_guts(0x22) -->
|
||||||
|
"\\\"", !.
|
||||||
|
pp_char_guts(0x27) -->
|
||||||
|
"\\'", !.
|
||||||
|
pp_char_guts(A) -->
|
||||||
|
{ A >= 0x20, A < 0x7F } ->
|
||||||
|
[A];
|
||||||
|
"\\x",
|
||||||
|
{ H is A >> 4, L is A /\ 0xF,
|
||||||
|
code_type(Hc, xdigit(H)),
|
||||||
|
code_type(Lc, xdigit(L)) },
|
||||||
|
[Hc,Lc].
|
||||||
|
|
||||||
|
pp_hexnum_guts(0) --> !.
|
||||||
|
pp_hexnum_guts(A) -->
|
||||||
|
{ L is A /\ 0xF,
|
||||||
|
H is A >> 4,
|
||||||
|
code_type(Lc, xdigit(L)) },
|
||||||
|
pp_hexnum_guts(H),
|
||||||
|
[Lc], !.
|
||||||
|
pp_string_guts([]) --> !.
|
||||||
|
pp_string_guts([X|Xs]) -->
|
||||||
|
pp_char_guts(X),
|
||||||
|
pp_string_guts(Xs), !.
|
||||||
|
|
||||||
|
pp_parser_args([]) --> !.
|
||||||
|
pp_parser_args([X|Rest]) -->
|
||||||
|
pp_parser(X),
|
||||||
|
pp_parser_args_rest(Rest).
|
||||||
|
pp_parser_args_rest([]) --> !.
|
||||||
|
pp_parser_args_rest([X|Xs]) -->
|
||||||
|
", ",
|
||||||
|
pp_parser(X),
|
||||||
|
pp_parser_args_rest(Xs).
|
||||||
|
|
||||||
|
pp_parser(parser(Name, Args)) -->
|
||||||
|
!,
|
||||||
|
{format_parser_name(Name,Fname)},
|
||||||
|
Fname,
|
||||||
|
"(",
|
||||||
|
pp_parser_args(Args),
|
||||||
|
")".
|
||||||
|
pp_parser(string(Str)) --> !,
|
||||||
|
"\"",
|
||||||
|
pp_string_guts(Str),
|
||||||
|
"\"", !.
|
||||||
|
pp_parser(num(0)) --> "0", !.
|
||||||
|
pp_parser(num(Num)) --> !,
|
||||||
|
( {Num < 0} ->
|
||||||
|
"-0x", {RNum is -Num}; "0x", {RNum = Num} ),
|
||||||
|
pp_hexnum_guts(RNum).
|
||||||
|
pp_parser(char(C)) --> !,
|
||||||
|
"'", pp_char_guts(C), "'", !.
|
||||||
|
|
||||||
|
pp_parser(ref(Name)) -->
|
||||||
|
{atom_codes(Name,CName)},
|
||||||
|
"sp_", CName, !.
|
||||||
|
|
||||||
|
|
||||||
|
pp_parser(A) -->
|
||||||
|
{ writef("WTF is a %w?\n", [A]),
|
||||||
|
!, fail
|
||||||
|
}.
|
||||||
|
|
||||||
|
pp_test_elem(decl, parser(_)) --> !.
|
||||||
|
pp_test_elem(init, parser(_)) --> !.
|
||||||
|
pp_test_elem(exec, parser(P)) -->
|
||||||
|
!, indent(3),
|
||||||
|
"parser = ",
|
||||||
|
pp_parser(P),
|
||||||
|
";\n".
|
||||||
|
pp_test_elem(decl, subparser(Name,_)) -->
|
||||||
|
!, indent(3),
|
||||||
|
"IndirectParser ", pp_parser(ref(Name)),
|
||||||
|
" = Hammer.Indirect();\n".
|
||||||
|
pp_test_elem(init, subparser(Name, Parser)) -->
|
||||||
|
!, indent(3),
|
||||||
|
pp_parser(ref(Name)), ".Bind(",
|
||||||
|
pp_parser(Parser),
|
||||||
|
");\n".
|
||||||
|
pp_test_elem(exec, subparser(_,_)) --> !.
|
||||||
|
pp_test_elem(decl, test(_,_)) --> !.
|
||||||
|
pp_test_elem(init, test(_,_)) --> !.
|
||||||
|
pp_test_elem(decl, testFail(_)) --> !.
|
||||||
|
pp_test_elem(init, testFail(_)) --> !.
|
||||||
|
pp_test_elem(exec, test(Str, Result)) -->
|
||||||
|
!, indent(3),
|
||||||
|
" CheckParseOK(parser, ", pp_parser(string(Str)),
|
||||||
|
", ",
|
||||||
|
pp_parse_result(Result),
|
||||||
|
");\n".
|
||||||
|
pp_test_elem(exec, testFail(Str)) -->
|
||||||
|
!, indent(3),
|
||||||
|
" CheckParseFail(parser, ", pp_parser(string(Str)),
|
||||||
|
");\n".
|
||||||
|
|
||||||
|
% pp_test_elem(_, _) --> !.
|
||||||
|
|
||||||
|
pp_result_seq([]) --> !.
|
||||||
|
pp_result_seq([X|Xs]) --> !,
|
||||||
|
pp_parse_result(X),
|
||||||
|
pp_result_seq_r(Xs).
|
||||||
|
pp_result_seq_r([]) --> !.
|
||||||
|
pp_result_seq_r([X|Xs]) --> !,
|
||||||
|
", ",
|
||||||
|
pp_parse_result(X),
|
||||||
|
pp_result_seq_r(Xs).
|
||||||
|
|
||||||
|
pp_byte_seq([]) --> !.
|
||||||
|
pp_byte_seq([X|Xs]) --> !,
|
||||||
|
pp_parser(num(X)),
|
||||||
|
pp_byte_seq_r(Xs).
|
||||||
|
pp_byte_seq_r([]) --> !.
|
||||||
|
pp_byte_seq_r([X|Xs]) --> !,
|
||||||
|
", ",
|
||||||
|
pp_parser(num(X)),
|
||||||
|
pp_byte_seq_r(Xs).
|
||||||
|
|
||||||
|
pp_parse_result(char(C)) --> !,
|
||||||
|
%"(System.UInt64)",
|
||||||
|
pp_parser(char(C)).
|
||||||
|
pp_parse_result(seq(Args)) --> !,
|
||||||
|
"new object[]{ ", pp_result_seq(Args), "}".
|
||||||
|
pp_parse_result(none) --> !,
|
||||||
|
"null".
|
||||||
|
pp_parse_result(uint(V)) --> !,
|
||||||
|
"(System.UInt64)", pp_parser(num(V)).
|
||||||
|
pp_parse_result(sint(V)) --> !,
|
||||||
|
"(System.Int64)(", pp_parser(num(V)), ")".
|
||||||
|
pp_parse_result(string(A)) --> !,
|
||||||
|
"new byte[]{ ", pp_byte_seq(A), "}".
|
||||||
|
%pp_parse_result(A) -->
|
||||||
|
% "\x1b[1;31m",
|
||||||
|
% {with_output_to(codes(C), write(A))},
|
||||||
|
% C,
|
||||||
|
% "\x1b[0m".
|
||||||
|
|
||||||
|
|
||||||
|
pp_test_elems(_, []) --> !.
|
||||||
|
pp_test_elems(Phase, [X|Xs]) -->
|
||||||
|
!,
|
||||||
|
pp_test_elem(Phase,X),
|
||||||
|
pp_test_elems(Phase,Xs).
|
||||||
|
|
||||||
|
pp_test_case(testcase(Name, Elems)) -->
|
||||||
|
!,
|
||||||
|
indent(2), "[Test]\n",
|
||||||
|
{ format_test_name(Name, TName) },
|
||||||
|
indent(2), "public void ", TName, "() {\n",
|
||||||
|
indent(3), "Parser parser;\n",
|
||||||
|
pp_test_elems(decl, Elems),
|
||||||
|
pp_test_elems(init, Elems),
|
||||||
|
pp_test_elems(exec, Elems),
|
||||||
|
indent(2), "}\n".
|
||||||
|
|
||||||
|
|
||||||
|
pp_test_cases([]) --> !.
|
||||||
|
pp_test_cases([A|As]) -->
|
||||||
|
pp_test_case(A),
|
||||||
|
pp_test_cases(As).
|
||||||
|
|
||||||
|
pp_test_suite(Suite) -->
|
||||||
|
"namespace Hammer.Test {\n",
|
||||||
|
indent(1), "using NUnit.Framework;\n",
|
||||||
|
%indent(1), "using Hammer;\n",
|
||||||
|
indent(1), "[TestFixture]\n",
|
||||||
|
indent(1), "public partial class HammerTest {\n",
|
||||||
|
pp_test_cases(Suite),
|
||||||
|
indent(1), "}\n",
|
||||||
|
"}\n".
|
||||||
|
|
||||||
|
gen_ts(Foo,Str) :-
|
||||||
|
phrase(pp_test_suite(Foo),Str).
|
||||||
|
|
||||||
|
prolog :-
|
||||||
|
read_tc(A),
|
||||||
|
gen_ts(A, Res),
|
||||||
|
writef("%s", [Res]).
|
||||||
1
src/bindings/dotnet/README.md
Normal file
1
src/bindings/dotnet/README.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
The minimum version of Mono required to use these bindings is 3.0.x. The 2.x series is not currently supported, though we'll happily accept a PR for one.
|
||||||
59
src/bindings/dotnet/SConscript
Normal file
59
src/bindings/dotnet/SConscript
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
# -*- python -*-
|
||||||
|
import os.path
|
||||||
|
Import("env libhammer_shared testruns targets")
|
||||||
|
|
||||||
|
dotnetenv = env.Clone()
|
||||||
|
|
||||||
|
dotnetenv.Append(CCFLAGS=["-fpic", '-DSWIG', '-Wno-all',
|
||||||
|
'-Wno-extra', '-Wno-error',
|
||||||
|
'-DHAMMER_INTERNAL__NO_STDARG_H'],
|
||||||
|
CPPPATH=["../.."],
|
||||||
|
LIBS=['hammer'],
|
||||||
|
LIBPATH=["../.."],
|
||||||
|
SWIGFLAGS=["-DHAMMER_INTERNAL__NO_STDARG_H",
|
||||||
|
"-Isrc/", "-csharp",
|
||||||
|
"-dllimport","hammer_dotnet",
|
||||||
|
"-namespace", "Hammer.Internal"])
|
||||||
|
import os
|
||||||
|
|
||||||
|
swig = ['hammer.i']
|
||||||
|
thisdir = os.path.join(os.path.dirname(str(libhammer_shared[0])), "bindings","dotnet")
|
||||||
|
csfiles = os.path.join(thisdir, "*.cs")
|
||||||
|
|
||||||
|
# These AlwaysBuilds are annoying, but alas there doesn't seem to be a
|
||||||
|
# better way. I'd love to be corrected. Send PRs!
|
||||||
|
|
||||||
|
# This also generates a bunch of .cs files, which we'll just use this
|
||||||
|
# target to stand in for.
|
||||||
|
hammer_wrap = AlwaysBuild(dotnetenv.Command(['hammer_wrap.c'], swig,
|
||||||
|
["rm %s/*.cs || true" % (thisdir,),
|
||||||
|
"swig $SWIGFLAGS $SOURCE"]))
|
||||||
|
libhammer_dotnet = dotnetenv.SharedLibrary(['hammer_dotnet'], hammer_wrap)
|
||||||
|
hammer_dll = AlwaysBuild(dotnetenv.Command(['hammer.dll'], Glob('ext/*.cs'),
|
||||||
|
'$CSC -t:library -unsafe -out:$TARGET %s/*.cs $SOURCE' %(thisdir,)))
|
||||||
|
Depends(hammer_dll, hammer_wrap)
|
||||||
|
Default(libhammer_dotnet, hammer_dll)
|
||||||
|
|
||||||
|
dotnettestenv = dotnetenv.Clone()
|
||||||
|
|
||||||
|
def makeCIL(env, cmd):
|
||||||
|
libs = cmd.split(' ')
|
||||||
|
for lib in libs:
|
||||||
|
env.Append(CILLIBS=[lib[3:]])
|
||||||
|
|
||||||
|
dotnettestenv.ParseConfig('pkg-config --libs nunit', makeCIL)
|
||||||
|
dotnettestenv.Append(CILLIBS=[thisdir + "/hammer.dll"])
|
||||||
|
dotnettestlib = dotnettestenv.CLILibrary('hammer_test.dll', Glob('test/*.cs'))
|
||||||
|
Depends(dotnettestlib, hammer_dll)
|
||||||
|
|
||||||
|
dotnettestenv['ENV']["LD_LIBRARY_PATH"] = ":".join([thisdir, os.path.dirname(str(libhammer_shared[0]))])
|
||||||
|
dotnettestexec = dotnettestenv.Command(None, dotnettestlib, "nunit-console $SOURCE")
|
||||||
|
Depends(dotnettestlib, hammer_dll)
|
||||||
|
Depends(dotnettestlib, libhammer_dotnet)
|
||||||
|
dotnettest = Alias("testdotnet", [dotnettestexec], dotnettestexec)
|
||||||
|
AlwaysBuild(dotnettestexec)
|
||||||
|
testruns.append(dotnettestexec)
|
||||||
|
|
||||||
|
#dotnetinstallexec = dotnetenv.Command(None, libhammer_dotnet, "make install -C " + targetdir)
|
||||||
|
#dotnetinstall = Alias("installdotnet", [dotnetinstallexec], dotnetinstallexec)
|
||||||
|
#targets.append(dotnetinstall)
|
||||||
388
src/bindings/dotnet/ext/hammer.cs
Normal file
388
src/bindings/dotnet/ext/hammer.cs
Normal file
|
|
@ -0,0 +1,388 @@
|
||||||
|
using Hammer.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Collections;
|
||||||
|
namespace Hammer
|
||||||
|
{
|
||||||
|
|
||||||
|
public delegate Object HAction(Object obj);
|
||||||
|
public delegate bool HPredicate(Object obj);
|
||||||
|
|
||||||
|
public class ParseError : Exception
|
||||||
|
{
|
||||||
|
public readonly string Reason;
|
||||||
|
public ParseError() : this(null) {}
|
||||||
|
public ParseError(string reason) : base() {
|
||||||
|
Reason = reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class Parser
|
||||||
|
{
|
||||||
|
internal HParser wrapped;
|
||||||
|
internal System.Collections.IList pins; // objects that need to stay in scope for this one
|
||||||
|
internal Parser(HParser parser)
|
||||||
|
{
|
||||||
|
wrapped = parser;
|
||||||
|
pins = new System.Collections.ArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Parser Pin(Object o)
|
||||||
|
{
|
||||||
|
pins.Add(o);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object Parse(byte[] str)
|
||||||
|
{
|
||||||
|
byte[] strp;
|
||||||
|
if (str.Length == 0)
|
||||||
|
strp = new byte[1];
|
||||||
|
else
|
||||||
|
strp = str;
|
||||||
|
try {
|
||||||
|
unsafe {
|
||||||
|
fixed(byte* b = &strp[0]) {
|
||||||
|
HParseResult res = hammer.h_parse(wrapped, (IntPtr)b, (uint)str.Length);
|
||||||
|
if (res != null) {
|
||||||
|
// TODO: free the PR
|
||||||
|
return Unmarshal(res.ast);
|
||||||
|
} else {
|
||||||
|
throw new ParseError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ParseError e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Object Unmarshal(HParsedToken tok)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
switch(tok.token_type) {
|
||||||
|
case HTokenType.TT_NONE:
|
||||||
|
return null;
|
||||||
|
case HTokenType.TT_BYTES:
|
||||||
|
{
|
||||||
|
byte[] ret = new byte[tok.token_data.bytes.len];
|
||||||
|
Marshal.Copy(tok.token_data.bytes.token,
|
||||||
|
ret,
|
||||||
|
0, ret.Length);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case HTokenType.TT_SINT:
|
||||||
|
return (System.Int64)tok.token_data.sint;
|
||||||
|
case HTokenType.TT_UINT:
|
||||||
|
return (System.UInt64)tok.token_data._uint;
|
||||||
|
case HTokenType.TT_SEQUENCE:
|
||||||
|
{
|
||||||
|
Object[] ret = new Object[tok.token_data.seq.used];
|
||||||
|
for (uint i = 0; i < ret.Length; i++)
|
||||||
|
ret[i] = Unmarshal(tok.token_data.seq.at(i));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if (tok.token_type == Hammer.tt_dotnet)
|
||||||
|
{
|
||||||
|
HTaggedToken tagged = hammer.h_parsed_token_get_tagged_token(tok);
|
||||||
|
Object cb = Hammer.tag_to_action[tagged.label];
|
||||||
|
Object unmarshalled = Unmarshal(tagged.token);
|
||||||
|
if (cb is HAction) {
|
||||||
|
HAction act = (HAction)cb;
|
||||||
|
return act(unmarshalled);
|
||||||
|
} else if (cb is HPredicate) {
|
||||||
|
HPredicate pred = (HPredicate)cb;
|
||||||
|
if (!pred(unmarshalled))
|
||||||
|
throw new ParseError("Predicate failed");
|
||||||
|
else
|
||||||
|
return unmarshalled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception("Should not reach here");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IndirectParser : Parser
|
||||||
|
{
|
||||||
|
internal IndirectParser(HParser parser)
|
||||||
|
: base(parser)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Bind(Parser p)
|
||||||
|
{
|
||||||
|
hammer.h_bind_indirect(this.wrapped, p.wrapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Hammer
|
||||||
|
{
|
||||||
|
internal static IDictionary tag_to_action;
|
||||||
|
internal static ulong charify_action;
|
||||||
|
internal static HTokenType tt_dotnet;
|
||||||
|
static Hammer()
|
||||||
|
{
|
||||||
|
tt_dotnet = hammer.h_allocate_token_type("com.upstandinghackers.hammer.dotnet.tagged");
|
||||||
|
hammer.h_set_dotnet_tagged_token_type(tt_dotnet);
|
||||||
|
tag_to_action = new System.Collections.Hashtable();
|
||||||
|
charify_action = RegisterAction(x => {
|
||||||
|
//System.Console.WriteLine(x.GetType());
|
||||||
|
return char.ConvertFromUtf32((int)(ulong)x)[0];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static ulong RegisterAction(HAction action)
|
||||||
|
{
|
||||||
|
ulong newAction = (ulong)tag_to_action.Count;
|
||||||
|
tag_to_action[newAction] = action;
|
||||||
|
return newAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static ulong RegisterPredicate(HPredicate predicate)
|
||||||
|
{
|
||||||
|
ulong newPredicate = (ulong)tag_to_action.Count;
|
||||||
|
tag_to_action[newPredicate] = predicate;
|
||||||
|
return newPredicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Parser CharParser(Parser p)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_tag(p.wrapped, charify_action)).Pin(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static byte[] ToBytes(string s)
|
||||||
|
{
|
||||||
|
// Probably not what you want unless you're parsing binary data.
|
||||||
|
// This is just a one-to-one encoding of the string's codepoints
|
||||||
|
byte[] ret = new byte[s.Length];
|
||||||
|
for (int i = 0; i < s.Length; i++)
|
||||||
|
{
|
||||||
|
ret[i] = (byte)s[i];
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static IntPtr[] BuildParserArray(Parser[] parsers)
|
||||||
|
{
|
||||||
|
IntPtr[] rlist = new IntPtr[parsers.Length+1];
|
||||||
|
for (int i = 0; i < parsers.Length; i++)
|
||||||
|
{
|
||||||
|
rlist[i] = HParser.getCPtr(parsers[i].wrapped).Handle;
|
||||||
|
}
|
||||||
|
rlist[parsers.Length] = IntPtr.Zero;
|
||||||
|
return rlist;
|
||||||
|
}
|
||||||
|
public static Parser Sequence(params Parser[] parsers)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
IntPtr[] plist = BuildParserArray(parsers);
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (IntPtr *pp = &plist[0])
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_sequence__a((IntPtr)pp)).Pin(parsers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Choice(params Parser[] parsers)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
IntPtr[] plist = BuildParserArray(parsers);
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (IntPtr *pp = &plist[0])
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_choice__a((IntPtr)pp)).Pin(parsers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IndirectParser Indirect()
|
||||||
|
{
|
||||||
|
return new IndirectParser(hammer.h_indirect());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Ch(byte ch)
|
||||||
|
{
|
||||||
|
return CharParser(new Parser(hammer.h_ch(ch)));
|
||||||
|
|
||||||
|
}
|
||||||
|
public static Parser Ch(char ch)
|
||||||
|
{
|
||||||
|
return Ch((byte)ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Ch_range(byte c1, byte c2)
|
||||||
|
{
|
||||||
|
return CharParser(new Parser(hammer.h_ch_range(c1, c2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Ch_range(char c1, char c2)
|
||||||
|
{
|
||||||
|
return CharParser(new Parser(hammer.h_ch_range((byte)c1, (byte)c2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Int_range(Parser p, System.Int64 i1, System.Int64 i2)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_int_range(p.wrapped, i1, i2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Token(byte[] token)
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
fixed(byte* b = &token[0])
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_token((IntPtr)b, (uint)token.Length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser In(byte[] charset)
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
fixed(byte* b = &charset[0])
|
||||||
|
{
|
||||||
|
return CharParser(new Parser(hammer.h_in((IntPtr)b, (uint)charset.Length)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Not_in(byte[] charset)
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
fixed(byte* b = &charset[0])
|
||||||
|
{
|
||||||
|
return CharParser(new Parser(hammer.h_not_in((IntPtr)b, (uint)charset.Length)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Token(string token)
|
||||||
|
{
|
||||||
|
// Encodes in UTF-8
|
||||||
|
return Token(ToBytes(token));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser In(string charset)
|
||||||
|
{
|
||||||
|
// Encodes in UTF-8
|
||||||
|
return In(ToBytes(charset));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Not_in(string charset)
|
||||||
|
{
|
||||||
|
// Encodes in UTF-8
|
||||||
|
return Not_in(ToBytes(charset));
|
||||||
|
}
|
||||||
|
|
||||||
|
// No-arg parsers
|
||||||
|
public static Parser Int8() {return new Parser(hammer.h_int8());}
|
||||||
|
public static Parser Int16() {return new Parser(hammer.h_int16());}
|
||||||
|
public static Parser Int32() {return new Parser(hammer.h_int32());}
|
||||||
|
public static Parser Int64() {return new Parser(hammer.h_int64());}
|
||||||
|
public static Parser Uint8() {return new Parser(hammer.h_uint8());}
|
||||||
|
public static Parser Uint16() {return new Parser(hammer.h_uint16());}
|
||||||
|
public static Parser Uint32() {return new Parser(hammer.h_uint32());}
|
||||||
|
public static Parser Uint64() {return new Parser(hammer.h_uint64());}
|
||||||
|
|
||||||
|
public static Parser End_p() {return new Parser(hammer.h_end_p());}
|
||||||
|
public static Parser Nothing_p() {return new Parser(hammer.h_nothing_p());}
|
||||||
|
public static Parser Epsilon_p() {return new Parser(hammer.h_epsilon_p());}
|
||||||
|
|
||||||
|
// 1-arg parsers
|
||||||
|
public static Parser Ignore(Parser p)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_ignore(p.wrapped)).Pin(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Not(Parser p)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_not(p.wrapped)).Pin(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Whitespace(Parser p)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_whitespace(p.wrapped)).Pin(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Optional(Parser p)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_optional(p.wrapped)).Pin(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser And(Parser p)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_and(p.wrapped)).Pin(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Many(Parser p)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_many(p.wrapped)).Pin(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser Many1(Parser p)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_many1(p.wrapped)).Pin(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser SepBy(Parser p, Parser sep)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_sepBy(p.wrapped, sep.wrapped)).Pin(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parser SepBy1(Parser p, Parser sep)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_sepBy1(p.wrapped, sep.wrapped)).Pin(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2-arg parsers
|
||||||
|
|
||||||
|
public static Parser Left(Parser p1, Parser p2)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_left(p1.wrapped, p2.wrapped)).Pin(p1).Pin(p2);
|
||||||
|
}
|
||||||
|
public static Parser Right(Parser p1, Parser p2)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_right(p1.wrapped, p2.wrapped));
|
||||||
|
}
|
||||||
|
public static Parser Xor(Parser p1, Parser p2)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_xor(p1.wrapped, p2.wrapped));
|
||||||
|
}
|
||||||
|
public static Parser Difference(Parser p1, Parser p2)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_difference(p1.wrapped, p2.wrapped));
|
||||||
|
}
|
||||||
|
public static Parser Butnot(Parser p1, Parser p2)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_butnot(p1.wrapped, p2.wrapped));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Multi-arg parsers
|
||||||
|
public static Parser Middle(Parser p1, Parser p2, Parser p3)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_middle(p1.wrapped, p2.wrapped, p3.wrapped));
|
||||||
|
}
|
||||||
|
public static Parser Repeat_n(Parser p, uint count)
|
||||||
|
{
|
||||||
|
return new Parser(hammer.h_repeat_n(p.wrapped, count));
|
||||||
|
}
|
||||||
|
public static Parser Action(Parser p, HAction action)
|
||||||
|
{
|
||||||
|
ulong actionNo = Hammer.RegisterAction(action);
|
||||||
|
return new Parser(hammer.h_tag(p.wrapped, actionNo)).Pin(p).Pin(action);
|
||||||
|
}
|
||||||
|
public static Parser AttrBool(Parser p, HPredicate predicate)
|
||||||
|
{
|
||||||
|
ulong predNo = Hammer.RegisterPredicate(predicate);
|
||||||
|
return new Parser(hammer.h_tag(p.wrapped, predNo)).Pin(p).Pin(predicate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
80
src/bindings/dotnet/hammer.i
Normal file
80
src/bindings/dotnet/hammer.i
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
%module hammer;
|
||||||
|
|
||||||
|
%include "stdint.i"
|
||||||
|
|
||||||
|
// Special attention needs to be paid to:
|
||||||
|
// h_parse
|
||||||
|
// h_token
|
||||||
|
// h_in
|
||||||
|
// h_not_in
|
||||||
|
|
||||||
|
//%typemap(cstype) uint8_t* "byte[]"
|
||||||
|
//%typemap(csin, pre="unsafe { fixed(byte* temp$csinput = &$csinput[0]) {", terminator="}}") uint8_t* "(IntPtr)temp$csinput"
|
||||||
|
//%typemap(csvarin) uint8_t
|
||||||
|
%typemap(imtype) uint8_t* "IntPtr"
|
||||||
|
%typemap(cstype) uint8_t* "IntPtr"
|
||||||
|
%typemap(csin) uint8_t* "$csinput"
|
||||||
|
%typemap(csvarout) uint8_t* %{
|
||||||
|
get {
|
||||||
|
return $imcall;
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
%typemap(imtype) void*[] "IntPtr"
|
||||||
|
%typemap(cstype) void*[] "IntPtr"
|
||||||
|
%typemap(csin) void*[] "$csinput"
|
||||||
|
|
||||||
|
%ignore h_bit_writer_get_buffer;
|
||||||
|
//%apply (char *STRING, size_t LENGTH) {(uint8_t* str, size_t len)};
|
||||||
|
//%apply (uint8_t* str, size_t len) {(const uint8_t* input, size_t length)}
|
||||||
|
//%apply (uint8_t* str, size_t len) {(const uint8_t* str, const size_t len)}
|
||||||
|
//%apply (uint8_t* str, size_t len) {(const uint8_t* charset, size_t length)}
|
||||||
|
|
||||||
|
%typemap(csclassmodifiers) SWIGTYPE "internal class";
|
||||||
|
%csmethodmodifiers "internal";
|
||||||
|
|
||||||
|
%extend HCountedArray_ {
|
||||||
|
HParsedToken* at(unsigned int posn) {
|
||||||
|
if (posn >= $self->used)
|
||||||
|
return NULL;
|
||||||
|
return $self->elements[posn];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%include "../swig/hammer.i";
|
||||||
|
|
||||||
|
%{
|
||||||
|
HTokenType dotnet_tagged_token_type;
|
||||||
|
%}
|
||||||
|
%inline {
|
||||||
|
void h_set_dotnet_tagged_token_type(HTokenType new_tt) {
|
||||||
|
dotnet_tagged_token_type = new_tt;
|
||||||
|
}
|
||||||
|
// Need this inline as well
|
||||||
|
struct HTaggedToken {
|
||||||
|
HParsedToken *token;
|
||||||
|
uint64_t label;
|
||||||
|
};
|
||||||
|
|
||||||
|
// this is to make it easier to access via SWIG
|
||||||
|
struct HTaggedToken *h_parsed_token_get_tagged_token(HParsedToken* hpt) {
|
||||||
|
return (struct HTaggedToken*)hpt->token_data.user;
|
||||||
|
}
|
||||||
|
|
||||||
|
HParsedToken *act_tag(const HParseResult* p, void* user_data) {
|
||||||
|
struct HTaggedToken *tagged = H_ALLOC(struct HTaggedToken);
|
||||||
|
tagged->label = *(uint64_t*)user_data;
|
||||||
|
tagged->token = p->ast;
|
||||||
|
return h_make(p->arena, dotnet_tagged_token_type, tagged);
|
||||||
|
}
|
||||||
|
|
||||||
|
HParser *h_tag__m(HAllocator *mm__, HParser *p, uint64_t tag) {
|
||||||
|
uint64_t *tagptr = h_new(uint64_t, 1);
|
||||||
|
*tagptr = tag;
|
||||||
|
return h_action__m(mm__, p, act_tag, tagptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
HParser *h_tag(HParser *p, uint64_t tag) {
|
||||||
|
return h_tag__m(&system_allocator, p, tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/bindings/dotnet/test/hammer_hand_tests.cs
Normal file
35
src/bindings/dotnet/test/hammer_hand_tests.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
namespace Hammer.Test
|
||||||
|
{
|
||||||
|
using NUnit.Framework;
|
||||||
|
[TestFixture]
|
||||||
|
public partial class HammerTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestAction()
|
||||||
|
{
|
||||||
|
Parser parser = Hammer.Action(Hammer.Sequence(Hammer.Choice(Hammer.Ch('a'),
|
||||||
|
Hammer.Ch('A')),
|
||||||
|
Hammer.Choice(Hammer.Ch('b'),
|
||||||
|
Hammer.Ch('B'))),
|
||||||
|
(HAction)(x => string.Join(",",(object[])x)));
|
||||||
|
CheckParseOK(parser, "ab", "a,b");
|
||||||
|
CheckParseOK(parser, "AB", "A,B");
|
||||||
|
CheckParseFail(parser, "XX");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestAttrBool()
|
||||||
|
{
|
||||||
|
Parser parser = Hammer.AttrBool(Hammer.Many1(Hammer.Choice(Hammer.Ch('a'),
|
||||||
|
Hammer.Ch('b'))),
|
||||||
|
(HPredicate)(x => {
|
||||||
|
object[] elems = (object[])x;
|
||||||
|
return elems.Length > 1 && (char)elems[0] == (char)elems[1];
|
||||||
|
}));
|
||||||
|
|
||||||
|
CheckParseOK(parser, "aa", new object[]{ 'a','a' });
|
||||||
|
CheckParseOK(parser, "bb", new object[]{ 'b','b' });
|
||||||
|
CheckParseFail(parser, "ab");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
316
src/bindings/dotnet/test/hammer_tests.cs
Normal file
316
src/bindings/dotnet/test/hammer_tests.cs
Normal file
|
|
@ -0,0 +1,316 @@
|
||||||
|
namespace Hammer.Test {
|
||||||
|
using NUnit.Framework;
|
||||||
|
[TestFixture]
|
||||||
|
public partial class HammerTest {
|
||||||
|
[Test]
|
||||||
|
public void TestToken() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Token("95\xa2");
|
||||||
|
CheckParseOK(parser, "95\xa2", new byte[]{ 0x39, 0x35, 0xa2});
|
||||||
|
CheckParseFail(parser, "95\xa2");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestCh() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Ch(0xa2);
|
||||||
|
CheckParseOK(parser, "\xa2", '\xa2');
|
||||||
|
CheckParseFail(parser, "\xa3");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestCh_range() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Ch_range(0x61, 0x63);
|
||||||
|
CheckParseOK(parser, "b", 'b');
|
||||||
|
CheckParseFail(parser, "d");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestInt64() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Int64();
|
||||||
|
CheckParseOK(parser, "\xff\xff\xff\xfe\x00\x00\x00\x00", (System.Int64)(-0x200000000));
|
||||||
|
CheckParseFail(parser, "\xff\xff\xff\xfe\x00\x00\x00");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestInt32() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Int32();
|
||||||
|
CheckParseOK(parser, "\xff\xfe\x00\x00", (System.Int64)(-0x20000));
|
||||||
|
CheckParseFail(parser, "\xff\xfe\x00");
|
||||||
|
CheckParseOK(parser, "\x00\x02\x00\x00", (System.Int64)(0x20000));
|
||||||
|
CheckParseFail(parser, "\x00\x02\x00");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestInt16() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Int16();
|
||||||
|
CheckParseOK(parser, "\xfe\x00", (System.Int64)(-0x200));
|
||||||
|
CheckParseFail(parser, "\xfe");
|
||||||
|
CheckParseOK(parser, "\x02\x00", (System.Int64)(0x200));
|
||||||
|
CheckParseFail(parser, "\x02");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestInt8() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Int8();
|
||||||
|
CheckParseOK(parser, "\x88", (System.Int64)(-0x78));
|
||||||
|
CheckParseFail(parser, "");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestUint64() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Uint64();
|
||||||
|
CheckParseOK(parser, "\x00\x00\x00\x02\x00\x00\x00\x00", (System.UInt64)0x200000000);
|
||||||
|
CheckParseFail(parser, "\x00\x00\x00\x02\x00\x00\x00");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestUint32() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Uint32();
|
||||||
|
CheckParseOK(parser, "\x00\x02\x00\x00", (System.UInt64)0x20000);
|
||||||
|
CheckParseFail(parser, "\x00\x02\x00");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestUint16() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Uint16();
|
||||||
|
CheckParseOK(parser, "\x02\x00", (System.UInt64)0x200);
|
||||||
|
CheckParseFail(parser, "\x02");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestUint8() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Uint8();
|
||||||
|
CheckParseOK(parser, "x", (System.UInt64)0x78);
|
||||||
|
CheckParseFail(parser, "");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestInt_range() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Int_range(Hammer.Uint8(), 0x3, 0x10);
|
||||||
|
CheckParseOK(parser, "\x05", (System.UInt64)0x5);
|
||||||
|
CheckParseFail(parser, "\x0b");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestWhitespace() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Whitespace(Hammer.Ch(0x61));
|
||||||
|
CheckParseOK(parser, "a", 'a');
|
||||||
|
CheckParseOK(parser, " a", 'a');
|
||||||
|
CheckParseOK(parser, " a", 'a');
|
||||||
|
CheckParseOK(parser, "\x09a", 'a');
|
||||||
|
CheckParseFail(parser, "_a");
|
||||||
|
parser = Hammer.Whitespace(Hammer.End_p());
|
||||||
|
CheckParseOK(parser, "", null);
|
||||||
|
CheckParseOK(parser, " ", null);
|
||||||
|
CheckParseFail(parser, " x");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestLeft() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Left(Hammer.Ch(0x61), Hammer.Ch(0x20));
|
||||||
|
CheckParseOK(parser, "a ", 'a');
|
||||||
|
CheckParseFail(parser, "a");
|
||||||
|
CheckParseFail(parser, " ");
|
||||||
|
CheckParseFail(parser, "ba");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestMiddle() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Middle(Hammer.Ch(' '), Hammer.Ch('a'), Hammer.Ch(' '));
|
||||||
|
CheckParseOK(parser, " a ", 'a');
|
||||||
|
CheckParseFail(parser, "a");
|
||||||
|
CheckParseFail(parser, " a");
|
||||||
|
CheckParseFail(parser, "a ");
|
||||||
|
CheckParseFail(parser, " b ");
|
||||||
|
CheckParseFail(parser, "ba ");
|
||||||
|
CheckParseFail(parser, " ab");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestIn() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.In("abc");
|
||||||
|
CheckParseOK(parser, "b", 'b');
|
||||||
|
CheckParseFail(parser, "d");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestNot_in() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Not_in("abc");
|
||||||
|
CheckParseOK(parser, "d", 'd');
|
||||||
|
CheckParseFail(parser, "a");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestEnd_p() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.End_p());
|
||||||
|
CheckParseOK(parser, "a", new object[]{ 'a'});
|
||||||
|
CheckParseFail(parser, "aa");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestNothing_p() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Nothing_p();
|
||||||
|
CheckParseFail(parser, "a");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestSequence() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.Ch('b'));
|
||||||
|
CheckParseOK(parser, "ab", new object[]{ 'a', 'b'});
|
||||||
|
CheckParseFail(parser, "a");
|
||||||
|
CheckParseFail(parser, "b");
|
||||||
|
parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.Whitespace(Hammer.Ch('b')));
|
||||||
|
CheckParseOK(parser, "ab", new object[]{ 'a', 'b'});
|
||||||
|
CheckParseOK(parser, "a b", new object[]{ 'a', 'b'});
|
||||||
|
CheckParseOK(parser, "a b", new object[]{ 'a', 'b'});
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestChoice() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Choice(Hammer.Ch('a'), Hammer.Ch('b'));
|
||||||
|
CheckParseOK(parser, "a", 'a');
|
||||||
|
CheckParseOK(parser, "b", 'b');
|
||||||
|
CheckParseOK(parser, "ab", 'a');
|
||||||
|
CheckParseFail(parser, "c");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestButnot() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Butnot(Hammer.Ch('a'), Hammer.Token("ab"));
|
||||||
|
CheckParseOK(parser, "a", 'a');
|
||||||
|
CheckParseFail(parser, "ab");
|
||||||
|
CheckParseOK(parser, "aa", 'a');
|
||||||
|
parser = Hammer.Butnot(Hammer.Ch_range('0', '9'), Hammer.Ch('6'));
|
||||||
|
CheckParseOK(parser, "5", '5');
|
||||||
|
CheckParseFail(parser, "6");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestDifference() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Difference(Hammer.Token("ab"), Hammer.Ch('a'));
|
||||||
|
CheckParseOK(parser, "ab", new byte[]{ 0x61, 0x62});
|
||||||
|
CheckParseFail(parser, "a");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestXor() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Xor(Hammer.Ch_range('0', '6'), Hammer.Ch_range('5', '9'));
|
||||||
|
CheckParseOK(parser, "0", '0');
|
||||||
|
CheckParseOK(parser, "9", '9');
|
||||||
|
CheckParseFail(parser, "5");
|
||||||
|
CheckParseFail(parser, "a");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestMany() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Many(Hammer.Choice(Hammer.Ch('a'), Hammer.Ch('b')));
|
||||||
|
CheckParseOK(parser, "", new object[]{ });
|
||||||
|
CheckParseOK(parser, "a", new object[]{ 'a'});
|
||||||
|
CheckParseOK(parser, "b", new object[]{ 'b'});
|
||||||
|
CheckParseOK(parser, "aabbaba", new object[]{ 'a', 'a', 'b', 'b', 'a', 'b', 'a'});
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestMany1() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Many1(Hammer.Choice(Hammer.Ch('a'), Hammer.Ch('b')));
|
||||||
|
CheckParseFail(parser, "");
|
||||||
|
CheckParseOK(parser, "a", new object[]{ 'a'});
|
||||||
|
CheckParseOK(parser, "b", new object[]{ 'b'});
|
||||||
|
CheckParseOK(parser, "aabbaba", new object[]{ 'a', 'a', 'b', 'b', 'a', 'b', 'a'});
|
||||||
|
CheckParseFail(parser, "daabbabadef");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestRepeat_n() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Repeat_n(Hammer.Choice(Hammer.Ch('a'), Hammer.Ch('b')), 0x2);
|
||||||
|
CheckParseFail(parser, "adef");
|
||||||
|
CheckParseOK(parser, "abdef", new object[]{ 'a', 'b'});
|
||||||
|
CheckParseFail(parser, "dabdef");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestOptional() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.Optional(Hammer.Choice(Hammer.Ch('b'), Hammer.Ch('c'))), Hammer.Ch('d'));
|
||||||
|
CheckParseOK(parser, "abd", new object[]{ 'a', 'b', 'd'});
|
||||||
|
CheckParseOK(parser, "acd", new object[]{ 'a', 'c', 'd'});
|
||||||
|
CheckParseOK(parser, "ad", new object[]{ 'a', null, 'd'});
|
||||||
|
CheckParseFail(parser, "aed");
|
||||||
|
CheckParseFail(parser, "ab");
|
||||||
|
CheckParseFail(parser, "ac");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestIgnore() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.Ignore(Hammer.Ch('b')), Hammer.Ch('c'));
|
||||||
|
CheckParseOK(parser, "abc", new object[]{ 'a', 'c'});
|
||||||
|
CheckParseFail(parser, "ac");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestSepBy() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.SepBy(Hammer.Choice(Hammer.Ch('1'), Hammer.Ch('2'), Hammer.Ch('3')), Hammer.Ch(','));
|
||||||
|
CheckParseOK(parser, "1,2,3", new object[]{ '1', '2', '3'});
|
||||||
|
CheckParseOK(parser, "1,3,2", new object[]{ '1', '3', '2'});
|
||||||
|
CheckParseOK(parser, "1,3", new object[]{ '1', '3'});
|
||||||
|
CheckParseOK(parser, "3", new object[]{ '3'});
|
||||||
|
CheckParseOK(parser, "", new object[]{ });
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestSepBy1() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.SepBy1(Hammer.Choice(Hammer.Ch('1'), Hammer.Ch('2'), Hammer.Ch('3')), Hammer.Ch(','));
|
||||||
|
CheckParseOK(parser, "1,2,3", new object[]{ '1', '2', '3'});
|
||||||
|
CheckParseOK(parser, "1,3,2", new object[]{ '1', '3', '2'});
|
||||||
|
CheckParseOK(parser, "1,3", new object[]{ '1', '3'});
|
||||||
|
CheckParseOK(parser, "3", new object[]{ '3'});
|
||||||
|
CheckParseFail(parser, "");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestAnd() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Sequence(Hammer.And(Hammer.Ch('0')), Hammer.Ch('0'));
|
||||||
|
CheckParseOK(parser, "0", new object[]{ '0'});
|
||||||
|
CheckParseFail(parser, "1");
|
||||||
|
parser = Hammer.Sequence(Hammer.And(Hammer.Ch('0')), Hammer.Ch('1'));
|
||||||
|
CheckParseFail(parser, "0");
|
||||||
|
CheckParseFail(parser, "1");
|
||||||
|
parser = Hammer.Sequence(Hammer.Ch('1'), Hammer.And(Hammer.Ch('2')));
|
||||||
|
CheckParseOK(parser, "12", new object[]{ '1'});
|
||||||
|
CheckParseFail(parser, "13");
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestNot() {
|
||||||
|
Parser parser;
|
||||||
|
parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.Choice(Hammer.Token("+"), Hammer.Token("++")), Hammer.Ch('b'));
|
||||||
|
CheckParseOK(parser, "a+b", new object[]{ 'a', new byte[]{ 0x2b}, 'b'});
|
||||||
|
CheckParseFail(parser, "a++b");
|
||||||
|
parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.Choice(Hammer.Sequence(Hammer.Token("+"), Hammer.Not(Hammer.Ch('+'))), Hammer.Token("++")), Hammer.Ch('b'));
|
||||||
|
CheckParseOK(parser, "a+b", new object[]{ 'a', new object[]{ new byte[]{ 0x2b}}, 'b'});
|
||||||
|
CheckParseOK(parser, "a++b", new object[]{ 'a', new byte[]{ 0x2b, 0x2b}, 'b'});
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestRightrec() {
|
||||||
|
Parser parser;
|
||||||
|
IndirectParser sp_rr = Hammer.Indirect();
|
||||||
|
sp_rr.Bind(Hammer.Choice(Hammer.Sequence(Hammer.Ch('a'), sp_rr), Hammer.Epsilon_p()));
|
||||||
|
parser = sp_rr;
|
||||||
|
CheckParseOK(parser, "a", new object[]{ 'a'});
|
||||||
|
CheckParseOK(parser, "aa", new object[]{ 'a', new object[]{ 'a'}});
|
||||||
|
CheckParseOK(parser, "aaa", new object[]{ 'a', new object[]{ 'a', new object[]{ 'a'}}});
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void TestAmbiguous() {
|
||||||
|
Parser parser;
|
||||||
|
IndirectParser sp_d = Hammer.Indirect();
|
||||||
|
IndirectParser sp_p = Hammer.Indirect();
|
||||||
|
IndirectParser sp_e = Hammer.Indirect();
|
||||||
|
sp_d.Bind(Hammer.Ch('d'));
|
||||||
|
sp_p.Bind(Hammer.Ch('+'));
|
||||||
|
sp_e.Bind(Hammer.Choice(Hammer.Sequence(sp_e, sp_p, sp_e), sp_d));
|
||||||
|
parser = sp_e;
|
||||||
|
CheckParseOK(parser, "d", 'd');
|
||||||
|
CheckParseOK(parser, "d+d", new object[]{ 'd', '+', 'd'});
|
||||||
|
CheckParseOK(parser, "d+d+d", new object[]{ new object[]{ 'd', '+', 'd'}, '+', 'd'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
125
src/bindings/dotnet/test/test_support.cs
Normal file
125
src/bindings/dotnet/test/test_support.cs
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
using System;
|
||||||
|
using Hammer;
|
||||||
|
namespace Hammer.Test
|
||||||
|
{
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
public partial class HammerTest
|
||||||
|
{
|
||||||
|
|
||||||
|
protected bool DeepEquals(Object o1, Object o2)
|
||||||
|
{
|
||||||
|
if (o1.Equals(o2))
|
||||||
|
return true;
|
||||||
|
if (o1.GetType() != o2.GetType())
|
||||||
|
return false;
|
||||||
|
if (o1 is byte[])
|
||||||
|
{
|
||||||
|
byte[] a1 = (byte[])o1, a2 = (byte[])o2;
|
||||||
|
if (a1.Length != a2.Length)
|
||||||
|
return false;
|
||||||
|
for (uint i = 0; i < a1.Length; i++)
|
||||||
|
if (a1[i] != a2[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (o1 is Object[])
|
||||||
|
{
|
||||||
|
Object[] a1 = (Object[])o1, a2 = (Object[])o2;
|
||||||
|
if (a1.Length != a2.Length)
|
||||||
|
return false;
|
||||||
|
for (uint i = 0; i < a1.Length; i++)
|
||||||
|
if (!DeepEquals(a1[i],a2[i]))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static string ToString(Object o)
|
||||||
|
{
|
||||||
|
if (o == null)
|
||||||
|
{
|
||||||
|
return "null";
|
||||||
|
}
|
||||||
|
if (o is byte[])
|
||||||
|
{
|
||||||
|
string ret = "<";
|
||||||
|
byte[] a = (byte[])o;
|
||||||
|
for (uint i = 0; i < a.Length; i++)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
ret += ".";
|
||||||
|
ret += a[i].ToString("X2");
|
||||||
|
}
|
||||||
|
ret += ">";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else if (o is Object[])
|
||||||
|
{
|
||||||
|
Object[] a = (Object[])o;
|
||||||
|
string ret = "[";
|
||||||
|
|
||||||
|
for (uint i = 0; i < a.Length; i++)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
ret += " ";
|
||||||
|
ret += ToString(a[i]);
|
||||||
|
}
|
||||||
|
ret += "]";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else if (o is System.Int64)
|
||||||
|
{
|
||||||
|
System.Int64 i = (System.Int64)o;
|
||||||
|
return (i < 0 ? "s-0x" : "s0x") + i.ToString("X");
|
||||||
|
}
|
||||||
|
else if (o is System.UInt64)
|
||||||
|
{
|
||||||
|
System.UInt64 i = (System.UInt64)o;
|
||||||
|
return "u0x" + i.ToString("X");
|
||||||
|
}
|
||||||
|
else if (o is System.String)
|
||||||
|
{
|
||||||
|
return "\"" + o.ToString() + "\"";
|
||||||
|
}
|
||||||
|
else if (o is System.Char)
|
||||||
|
{
|
||||||
|
return "\'" + o.ToString() + "\'";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return "WAT(" + o.GetType() + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal static byte[] ToBytes(string s)
|
||||||
|
{
|
||||||
|
// Probably not what you want unless you're parsing binary data.
|
||||||
|
// This is just a one-to-one encoding of the string's codepoints
|
||||||
|
byte []ret = new byte[s.Length];
|
||||||
|
for (int i = 0; i < s.Length; i++)
|
||||||
|
{
|
||||||
|
ret[i] = (byte)s[i];
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void CheckParseOK(Parser p, string probe, Object expected)
|
||||||
|
{
|
||||||
|
Object ret = p.Parse(ToBytes(probe));
|
||||||
|
Assert.That(ret, Is.Not.Null);
|
||||||
|
//System.Console.WriteLine(ToString(ret));
|
||||||
|
//System.Console.WriteLine(ToString(expected));
|
||||||
|
if (!DeepEquals(ret, expected))
|
||||||
|
Assert.Fail();
|
||||||
|
else
|
||||||
|
Assert.Pass();
|
||||||
|
}
|
||||||
|
protected void CheckParseFail(Parser p, string probe)
|
||||||
|
{
|
||||||
|
Object ret = p.Parse(ToBytes(probe));
|
||||||
|
Assert.That(ret, Is.Null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,7 @@ pytests = ['hammer_tests.py']
|
||||||
pytestexec = pytestenv.Command(['hammer.pyc', 'hammer_tests.pyc'], pytests + libhammer_python, "LD_LIBRARY_PATH=" + os.path.dirname(str(libhammer_shared[0])) + " nosetests -vv $SOURCE")
|
pytestexec = pytestenv.Command(['hammer.pyc', 'hammer_tests.pyc'], pytests + libhammer_python, "LD_LIBRARY_PATH=" + os.path.dirname(str(libhammer_shared[0])) + " nosetests -vv $SOURCE")
|
||||||
pytest = Alias("testpython", [pytestexec], pytestexec)
|
pytest = Alias("testpython", [pytestexec], pytestexec)
|
||||||
AlwaysBuild(pytestexec)
|
AlwaysBuild(pytestexec)
|
||||||
testruns.extend(pytest)
|
testruns.append(pytest)
|
||||||
|
|
||||||
pyinstallexec = pythonenv.Command(None, libhammer_python, 'python ' + os.path.join(pydir, 'setup.py ') + ' install')
|
pyinstallexec = pythonenv.Command(None, libhammer_python, 'python ' + os.path.join(pydir, 'setup.py ') + ' install')
|
||||||
pyinstall = Alias("installpython", [pyinstallexec], pyinstallexec)
|
pyinstall = Alias("installpython", [pyinstallexec], pyinstallexec)
|
||||||
|
|
|
||||||
|
|
@ -666,13 +666,13 @@ void h_benchmark_report(FILE* stream, HBenchmarkResults* results);
|
||||||
|
|
||||||
// {{{ Token type registry
|
// {{{ Token type registry
|
||||||
/// Allocate a new, unused (as far as this function knows) token type.
|
/// Allocate a new, unused (as far as this function knows) token type.
|
||||||
int h_allocate_token_type(const char* name);
|
HTokenType h_allocate_token_type(const char* name);
|
||||||
|
|
||||||
/// Get the token type associated with name. Returns -1 if name is unkown
|
/// Get the token type associated with name. Returns -1 if name is unkown
|
||||||
int h_get_token_type_number(const char* name);
|
HTokenType h_get_token_type_number(const char* name);
|
||||||
|
|
||||||
/// Get the name associated with token_type. Returns NULL if the token type is unkown
|
/// Get the name associated with token_type. Returns NULL if the token type is unkown
|
||||||
const char* h_get_token_type_name(int token_type);
|
const char* h_get_token_type_name(HTokenType token_type);
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,14 @@
|
||||||
|
|
||||||
typedef struct Entry_ {
|
typedef struct Entry_ {
|
||||||
const char* name;
|
const char* name;
|
||||||
int value;
|
HTokenType value;
|
||||||
} Entry;
|
} Entry;
|
||||||
|
|
||||||
static void *tt_registry = NULL;
|
static void *tt_registry = NULL;
|
||||||
static Entry** tt_by_id = NULL;
|
static Entry** tt_by_id = NULL;
|
||||||
static int tt_by_id_sz = 0;
|
static unsigned int tt_by_id_sz = 0;
|
||||||
#define TT_START TT_USER
|
#define TT_START TT_USER
|
||||||
static int tt_next = TT_START;
|
static HTokenType tt_next = TT_START;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// TODO: These are for the extension registry, which does not yet have a good name.
|
// TODO: These are for the extension registry, which does not yet have a good name.
|
||||||
|
|
@ -45,12 +45,12 @@ static int compare_entries(const void* v1, const void* v2) {
|
||||||
return strcmp(e1->name, e2->name);
|
return strcmp(e1->name, e2->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int h_allocate_token_type(const char* name) {
|
HTokenType h_allocate_token_type(const char* name) {
|
||||||
Entry* new_entry = malloc(sizeof(*new_entry));
|
Entry* new_entry = malloc(sizeof(*new_entry));
|
||||||
new_entry->name = name;
|
new_entry->name = name;
|
||||||
new_entry->value = -1;
|
new_entry->value = 0;
|
||||||
Entry* probe = *(Entry**)tsearch(new_entry, &tt_registry, compare_entries);
|
Entry* probe = *(Entry**)tsearch(new_entry, &tt_registry, compare_entries);
|
||||||
if (probe->value != -1) {
|
if (probe->value != 0) {
|
||||||
// Token type already exists...
|
// Token type already exists...
|
||||||
// TODO: treat this as a bug?
|
// TODO: treat this as a bug?
|
||||||
free(new_entry);
|
free(new_entry);
|
||||||
|
|
@ -70,16 +70,16 @@ int h_allocate_token_type(const char* name) {
|
||||||
return probe->value;
|
return probe->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int h_get_token_type_number(const char* name) {
|
HTokenType h_get_token_type_number(const char* name) {
|
||||||
Entry e;
|
Entry e;
|
||||||
e.name = name;
|
e.name = name;
|
||||||
Entry **ret = (Entry**)tfind(&e, &tt_registry, compare_entries);
|
Entry **ret = (Entry**)tfind(&e, &tt_registry, compare_entries);
|
||||||
if (ret == NULL)
|
if (ret == NULL)
|
||||||
return -1;
|
return 0;
|
||||||
else
|
else
|
||||||
return (*ret)->value;
|
return (*ret)->value;
|
||||||
}
|
}
|
||||||
const char* h_get_token_type_name(int token_type) {
|
const char* h_get_token_type_name(HTokenType token_type) {
|
||||||
if (token_type >= tt_next || token_type < TT_START)
|
if (token_type >= tt_next || token_type < TT_START)
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ static void test_tt_registry(void) {
|
||||||
g_test_message("Unknown token type should not return a name");
|
g_test_message("Unknown token type should not return a name");
|
||||||
g_test_fail();
|
g_test_fail();
|
||||||
}
|
}
|
||||||
g_check_cmp_int32(h_get_token_type_number("com.upstandinghackers.test.unkown_token_type"), ==, -1);
|
g_check_cmp_int32(h_get_token_type_number("com.upstandinghackers.test.unkown_token_type"), ==, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void register_misc_tests(void) {
|
void register_misc_tests(void) {
|
||||||
|
|
|
||||||
1
tools/csharp/.hgignore
Normal file
1
tools/csharp/.hgignore
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
.*~
|
||||||
1
tools/csharp/README
Normal file
1
tools/csharp/README
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Grabbed from https://bitbucket.org/russel/scons_csharp, revision 058956ce21722f806a560c24305775f74dd71d3f
|
||||||
24
tools/csharp/__init__.py
Normal file
24
tools/csharp/__init__.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# -*- coding:utf-8; -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2012 The SCons Foundation
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
# a copy of this software and associated documentation files (the
|
||||||
|
# "Software"), to deal in the Software without restriction, including
|
||||||
|
# without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
# permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
# the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included
|
||||||
|
# in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
from csharp import exists, generate
|
||||||
503
tools/csharp/csharp.py
Normal file
503
tools/csharp/csharp.py
Normal file
|
|
@ -0,0 +1,503 @@
|
||||||
|
# -*- coding:utf-8; -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2009-10 The SCons Foundation
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
# a copy of this software and associated documentation files (the
|
||||||
|
# "Software"), to deal in the Software without restriction, including
|
||||||
|
# without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
# permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
# the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included
|
||||||
|
# in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
# This C# Tool taken from http://www.scons.org/wiki/CsharpBuilder and amended
|
||||||
|
# by the patch from Issue 1912 at http://scons.tigris.org/issues/show_bug.cgi?id=1912
|
||||||
|
|
||||||
|
# Amended and extended by Russel Winder <russel.winder@concertant.com>
|
||||||
|
|
||||||
|
# On the SCons wiki page there are two distinct tools, one for the Microsoft C# system and one for Mono.
|
||||||
|
# This is an attempt to meld to two based initially on the Microsoft C# tool with amendmnets from the Mono
|
||||||
|
# tool.
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
import SCons.Builder
|
||||||
|
import SCons.Node.FS
|
||||||
|
import SCons.Util
|
||||||
|
from SCons.Node.Python import Value
|
||||||
|
|
||||||
|
# needed for adding methods to environment
|
||||||
|
from SCons.Script.SConscript import SConsEnvironment
|
||||||
|
|
||||||
|
# parses env['VERSION'] for major, minor, build, and revision
|
||||||
|
def parseVersion(env):
|
||||||
|
"""parses env['VERSION'] for major, minor, build, and revision"""
|
||||||
|
if type(env['VERSION']) is tuple or type(env['VERSION']) is list:
|
||||||
|
major, minor, build, revision = env['VERSION']
|
||||||
|
elif type(env['VERSION']) is str:
|
||||||
|
major, minor, build, revision = env['VERSION'].split('.')
|
||||||
|
major = int(major)
|
||||||
|
minor = int(minor)
|
||||||
|
build = int(build)
|
||||||
|
revision = int(revision)
|
||||||
|
return (major, minor, build, revision)
|
||||||
|
|
||||||
|
def getVersionAsmDirective(major, minor, build, revision):
|
||||||
|
return '[assembly: AssemblyVersion("%d.%d.%d.%d")]' % (major, minor, build, revision)
|
||||||
|
|
||||||
|
def generateVersionId(env, target, source):
|
||||||
|
out = open(target[0].path, 'w')
|
||||||
|
out.write('using System;using System.Reflection;using System.Runtime.CompilerServices;using System.Runtime.InteropServices;\n')
|
||||||
|
out.write(source[0].get_contents())
|
||||||
|
out.close()
|
||||||
|
|
||||||
|
# used so that we can capture the return value of an executed command
|
||||||
|
def subprocess(cmdline):
|
||||||
|
"""used so that we can capture the return value of an executed command"""
|
||||||
|
import subprocess
|
||||||
|
startupinfo = subprocess.STARTUPINFO()
|
||||||
|
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||||
|
proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE, startupinfo=startupinfo, shell=False)
|
||||||
|
data, err = proc.communicate()
|
||||||
|
return proc.wait(), data, err
|
||||||
|
|
||||||
|
def generatePublisherPolicyConfig(env, target, source):
|
||||||
|
"""this method assumes that source list corresponds to [0]=version, [1]=assembly base name, [2]=assembly file node"""
|
||||||
|
# call strong name tool against compiled assembly and parse output for public token
|
||||||
|
outputFolder = os.path.split(target[0].tpath)[0]
|
||||||
|
pubpolicy = os.path.join(outputFolder, source[2].name)
|
||||||
|
rv, data, err = subprocess('sn -T ' + pubpolicy)
|
||||||
|
import re
|
||||||
|
tok_re = re.compile(r"([a-z0-9]{16})[\r\n ]{0,3}$")
|
||||||
|
match = tok_re.search(data)
|
||||||
|
tok = match.group(1)
|
||||||
|
|
||||||
|
# calculate version range to redirect from
|
||||||
|
version = source[0].value
|
||||||
|
oldVersionStartRange = '%s.%s.0.0' % (version[0], version[1])
|
||||||
|
newVersion = '%s.%s.%s.%s' % (version[0], version[1], version[2], version[3])
|
||||||
|
build = int(version[2])
|
||||||
|
rev = int(version[3])
|
||||||
|
|
||||||
|
# on build 0 and rev 0 or 1, no range is needed. otherwise calculate range
|
||||||
|
if (build == 0 and (rev == 0 or rev == 1)):
|
||||||
|
oldVersionRange = oldVersionStartRange
|
||||||
|
else:
|
||||||
|
if rev - 1 < 0:
|
||||||
|
endRevisionRange = '99'
|
||||||
|
endBuildRange = str(build-1)
|
||||||
|
else:
|
||||||
|
endRevisionRange = str(rev - 1)
|
||||||
|
endBuildRange = str(build)
|
||||||
|
oldVersionEndRange = '%s.%s.%s.%s' % (version[0], version[1], endBuildRange, endRevisionRange)
|
||||||
|
oldVersionRange = '%s-%s' % (oldVersionStartRange, oldVersionEndRange)
|
||||||
|
|
||||||
|
# write .net config xml out to file
|
||||||
|
out = open(target[0].path, 'w')
|
||||||
|
out.write('''\
|
||||||
|
<configuration><runtime><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="%s" publicKeyToken="%s"/>
|
||||||
|
<bindingRedirect oldVersion="%s" newVersion="%s"/>
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding></runtime></configuration>
|
||||||
|
''' % (source[1].value, tok, oldVersionRange, newVersion))
|
||||||
|
out.close()
|
||||||
|
|
||||||
|
def getKeyFile(node, sources):
|
||||||
|
"""search for key file"""
|
||||||
|
for file in node.children():
|
||||||
|
if file.name.endswith('.snk'):
|
||||||
|
sources.append(file)
|
||||||
|
return
|
||||||
|
|
||||||
|
# if not found look in included netmodules (first found is used)
|
||||||
|
for file in node.children():
|
||||||
|
if file.name.endswith('.netmodule'):
|
||||||
|
for file2 in file.children():
|
||||||
|
if file2.name.endswith('.snk'):
|
||||||
|
sources.append(file2)
|
||||||
|
return
|
||||||
|
|
||||||
|
def PublisherPolicy(env, target, **kw):
|
||||||
|
"""creates the publisher policy dll, mapping the major.minor.0.0 calls to the
|
||||||
|
major, minor, build, and revision passed in through the dictionary VERSION key"""
|
||||||
|
sources = []
|
||||||
|
# get version and generate .config file
|
||||||
|
version = parseVersion(kw)
|
||||||
|
asm = os.path.splitext(target[0].name)[0]
|
||||||
|
configName = 'policy.%d.%d.%s.%s' % (version[0], version[1], asm, 'config')
|
||||||
|
targ = 'policy.%d.%d.%s' % (version[0], version[1], target[0].name)
|
||||||
|
config = env.Command(configName, [Value(version), Value(asm), target[0]], generatePublisherPolicyConfig)
|
||||||
|
sources.append(config[0])
|
||||||
|
|
||||||
|
# find .snk key
|
||||||
|
getKeyFile(target[0], sources)
|
||||||
|
|
||||||
|
return env.CLIAsmLink(targ, sources, **kw)
|
||||||
|
|
||||||
|
def CLIRefs(env, refs, paths = [], **kw):
|
||||||
|
listRefs = []
|
||||||
|
normpaths = [env.Dir(p).abspath for p in paths]
|
||||||
|
normpaths += env['CLIREFPATHS']
|
||||||
|
|
||||||
|
for ref in refs:
|
||||||
|
if not ref.endswith(env['SHLIBSUFFIX']):
|
||||||
|
ref += env['SHLIBSUFFIX']
|
||||||
|
if not ref.startswith(env['SHLIBPREFIX']):
|
||||||
|
ref = env['SHLIBPREFIX'] + ref
|
||||||
|
pathref = detectRef(ref, normpaths, env)
|
||||||
|
if pathref:
|
||||||
|
listRefs.append(pathref)
|
||||||
|
|
||||||
|
return listRefs
|
||||||
|
|
||||||
|
def CLIMods(env, refs, paths = [], **kw):
|
||||||
|
listMods = []
|
||||||
|
normpaths = [env.Dir(p).abspath for p in paths]
|
||||||
|
normpaths += env['CLIMODPATHS']
|
||||||
|
|
||||||
|
for ref in refs:
|
||||||
|
if not ref.endswith(env['CLIMODSUFFIX']):
|
||||||
|
ref += env['CLIMODSUFFIX']
|
||||||
|
pathref = detectRef(ref, normpaths, env)
|
||||||
|
if pathref:
|
||||||
|
listMods.append(pathref)
|
||||||
|
|
||||||
|
return listMods
|
||||||
|
|
||||||
|
def detectRef(ref, paths, env):
|
||||||
|
"""look for existance of file (ref) at one of the paths"""
|
||||||
|
for path in paths:
|
||||||
|
if path.endswith(ref):
|
||||||
|
return path
|
||||||
|
pathref = os.path.join(path, ref)
|
||||||
|
if os.path.isfile(pathref):
|
||||||
|
return pathref
|
||||||
|
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def AddToRefPaths(env, files, **kw):
|
||||||
|
# the file name is included in path reference because otherwise checks for that output file
|
||||||
|
# by CLIRefs/CLIMods would fail until after it has been built. Since SCons makes a pass
|
||||||
|
# before building anything, that file won't be there. Only after the second pass will it be built
|
||||||
|
ref = env.FindIxes(files, 'SHLIBPREFIX', 'SHLIBSUFFIX').abspath
|
||||||
|
env['CLIREFPATHS'] = [ref] + env['CLIREFPATHS']
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def AddToModPaths(env, files, **kw):
|
||||||
|
mod = env.FindIxes(files, 'CLIMODPREFIX', 'CLIMODSUFFIX').abspath
|
||||||
|
env['CLIMODPATHS'] = [mod] + env['CLIMODPATHS']
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def cscFlags(target, source, env, for_signature):
|
||||||
|
listCmd = []
|
||||||
|
if (env.has_key('WINEXE')):
|
||||||
|
if (env['WINEXE'] == 1):
|
||||||
|
listCmd.append('-t:winexe')
|
||||||
|
return listCmd
|
||||||
|
|
||||||
|
def cscSources(target, source, env, for_signature):
|
||||||
|
listCmd = []
|
||||||
|
|
||||||
|
for s in source:
|
||||||
|
if (str(s).endswith('.cs')): # do this first since most will be source files
|
||||||
|
listCmd.append(s)
|
||||||
|
elif (str(s).endswith('.resources')):
|
||||||
|
listCmd.append('-resource:%s' % s.get_string(for_signature))
|
||||||
|
elif (str(s).endswith('.snk')):
|
||||||
|
listCmd.append('-keyfile:%s' % s.get_string(for_signature))
|
||||||
|
else:
|
||||||
|
# just treat this as a generic unidentified source file
|
||||||
|
listCmd.append(s)
|
||||||
|
|
||||||
|
return listCmd
|
||||||
|
|
||||||
|
def cscSourcesNoResources(target, source, env, for_signature):
|
||||||
|
listCmd = []
|
||||||
|
|
||||||
|
for s in source:
|
||||||
|
if (str(s).endswith('.cs')): # do this first since most will be source files
|
||||||
|
listCmd.append(s)
|
||||||
|
elif (str(s).endswith('.resources')): # resources cannot be embedded in netmodules
|
||||||
|
pass
|
||||||
|
elif (str(s).endswith('.snk')):
|
||||||
|
listCmd.append('-keyfile:%s' % s.get_string(for_signature))
|
||||||
|
else:
|
||||||
|
# just treat this as a generic unidentified source file
|
||||||
|
listCmd.append(s)
|
||||||
|
|
||||||
|
return listCmd
|
||||||
|
|
||||||
|
def cscRefs(target, source, env, for_signature):
|
||||||
|
listCmd = []
|
||||||
|
|
||||||
|
if (env.has_key('ASSEMBLYREFS')):
|
||||||
|
refs = SCons.Util.flatten(env['ASSEMBLYREFS'])
|
||||||
|
for ref in refs:
|
||||||
|
if SCons.Util.is_String(ref):
|
||||||
|
listCmd.append('-reference:%s' % ref)
|
||||||
|
else:
|
||||||
|
listCmd.append('-reference:%s' % ref.abspath)
|
||||||
|
|
||||||
|
return listCmd
|
||||||
|
|
||||||
|
def cscMods(target, source, env, for_signature):
|
||||||
|
listCmd = []
|
||||||
|
|
||||||
|
if (env.has_key('NETMODULES')):
|
||||||
|
mods = SCons.Util.flatten(env['NETMODULES'])
|
||||||
|
for mod in mods:
|
||||||
|
listCmd.append('-addmodule:%s' % mod)
|
||||||
|
|
||||||
|
return listCmd
|
||||||
|
|
||||||
|
# TODO: this currently does not allow sources to be embedded (-embed flag)
|
||||||
|
def alLinkSources(target, source, env, for_signature):
|
||||||
|
listCmd = []
|
||||||
|
|
||||||
|
for s in source:
|
||||||
|
if (str(s).endswith('.snk')):
|
||||||
|
listCmd.append('-keyfile:%s' % s.get_string(for_signature))
|
||||||
|
else:
|
||||||
|
# just treat this as a generic unidentified source file
|
||||||
|
listCmd.append('-link:%s' % s.get_string(for_signature))
|
||||||
|
|
||||||
|
if env.has_key('VERSION'):
|
||||||
|
version = parseVersion(env)
|
||||||
|
listCmd.append('-version:%d.%d.%d.%d' % version)
|
||||||
|
|
||||||
|
return listCmd
|
||||||
|
|
||||||
|
def cliLinkSources(target, source, env, for_signature):
|
||||||
|
listCmd = []
|
||||||
|
|
||||||
|
# append source item. if it is a netmodule and has child resources, also append those
|
||||||
|
for s in source:
|
||||||
|
# all source items should go into listCmd
|
||||||
|
listCmd.append('%s' % s.get_string(for_signature))
|
||||||
|
|
||||||
|
if (str(s).endswith('.netmodule')):
|
||||||
|
for child in s.children():
|
||||||
|
if child.name.endswith('.resources'):
|
||||||
|
listCmd.append('/assemblyresource:%s' % child.get_string(for_signature))
|
||||||
|
|
||||||
|
return listCmd
|
||||||
|
|
||||||
|
def add_version(target, source, env):
|
||||||
|
if env.has_key('VERSION'):
|
||||||
|
if SCons.Util.is_String(target[0]):
|
||||||
|
versionfile = target[0] + '_VersionInfo.cs'
|
||||||
|
else:
|
||||||
|
versionfile = target[0].name + '_VersionInfo.cs'
|
||||||
|
source.append(env.Command(versionfile, [Value(getVersionAsmDirective(*parseVersion(env)))], generateVersionId))
|
||||||
|
return (target, source)
|
||||||
|
|
||||||
|
# this check is needed because .NET assemblies like to have '.' in the name.
|
||||||
|
# scons interprets that as an extension and doesn't append the suffix as a result
|
||||||
|
def lib_emitter(target, source, env):
|
||||||
|
newtargets = []
|
||||||
|
for tnode in target:
|
||||||
|
t = tnode.name
|
||||||
|
if not t.endswith(env['SHLIBSUFFIX']):
|
||||||
|
t += env['SHLIBSUFFIX']
|
||||||
|
newtargets.append(t)
|
||||||
|
|
||||||
|
return (newtargets, source)
|
||||||
|
|
||||||
|
def add_depends(target, source, env):
|
||||||
|
"""Add dependency information before the build order is established"""
|
||||||
|
|
||||||
|
if (env.has_key('NETMODULES')):
|
||||||
|
mods = SCons.Util.flatten(env['NETMODULES'])
|
||||||
|
for mod in mods:
|
||||||
|
# add as dependency
|
||||||
|
for t in target:
|
||||||
|
env.Depends(t, mod)
|
||||||
|
|
||||||
|
if (env.has_key('ASSEMBLYREFS')):
|
||||||
|
refs = SCons.Util.flatten(env['ASSEMBLYREFS'])
|
||||||
|
for ref in refs:
|
||||||
|
# add as dependency
|
||||||
|
for t in target:
|
||||||
|
env.Depends(t, ref)
|
||||||
|
|
||||||
|
return (target, source)
|
||||||
|
|
||||||
|
csc_action = SCons.Action.Action('$CSCCOM', '$CSCCOMSTR')
|
||||||
|
|
||||||
|
MsCliBuilder = SCons.Builder.Builder(action = '$CSCCOM',
|
||||||
|
source_factory = SCons.Node.FS.default_fs.Entry,
|
||||||
|
emitter = add_version,
|
||||||
|
suffix = '.exe')
|
||||||
|
|
||||||
|
csclib_action = SCons.Action.Action('$CSCLIBCOM', '$CSCLIBCOMSTR')
|
||||||
|
|
||||||
|
MsCliLibBuilder = SCons.Builder.Builder(action = '$CSCLIBCOM',
|
||||||
|
source_factory = SCons.Node.FS.default_fs.Entry,
|
||||||
|
emitter = [lib_emitter, add_version, add_depends],
|
||||||
|
suffix = '$SHLIBSUFFIX')
|
||||||
|
|
||||||
|
cscmod_action = SCons.Action.Action('$CSCMODCOM', '$CSCMODCOMSTR')
|
||||||
|
|
||||||
|
MsCliModBuilder = SCons.Builder.Builder(action = '$CSCMODCOM',
|
||||||
|
source_factory = SCons.Node.FS.default_fs.Entry,
|
||||||
|
emitter = [add_version, add_depends],
|
||||||
|
suffix = '$CLIMODSUFFIX')
|
||||||
|
|
||||||
|
def module_deps(target, source, env):
|
||||||
|
for s in source:
|
||||||
|
dir = s.dir.srcdir
|
||||||
|
if (dir is not None and dir is not type(None)):
|
||||||
|
for t in target:
|
||||||
|
env.Depends(t,s)
|
||||||
|
return (target, source)
|
||||||
|
|
||||||
|
clilink_action = SCons.Action.Action('$CLILINKCOM', '$CLILINKCOMSTR')
|
||||||
|
|
||||||
|
MsCliLinkBuilder = SCons.Builder.Builder(action = '$CLILINKCOM',
|
||||||
|
source_factory = SCons.Node.FS.default_fs.Entry,
|
||||||
|
emitter = [lib_emitter, add_version, module_deps], # don't know the best way yet to get module dependencies added
|
||||||
|
suffix = '.dll') #'$SHLIBSUFFIX')
|
||||||
|
|
||||||
|
# TODO : This probably needs some more work... it hasn't been used since
|
||||||
|
# finding the abilities of the VS 2005 C++ linker for .NET.
|
||||||
|
MsCliAsmLinkBuilder = SCons.Builder.Builder(action = '$CLIASMLINKCOM',
|
||||||
|
source_factory = SCons.Node.FS.default_fs.Entry,
|
||||||
|
suffix = '.dll')
|
||||||
|
|
||||||
|
typelib_prefix = 'Interop.'
|
||||||
|
|
||||||
|
def typelib_emitter(target, source, env):
|
||||||
|
newtargets = []
|
||||||
|
for tnode in target:
|
||||||
|
t = tnode.name
|
||||||
|
if not t.startswith(typelib_prefix):
|
||||||
|
t = typelib_prefix + t
|
||||||
|
newtargets.append(t)
|
||||||
|
|
||||||
|
return (newtargets, source)
|
||||||
|
|
||||||
|
def tlbimpFlags(target, source, env, for_signature):
|
||||||
|
listCmd = []
|
||||||
|
|
||||||
|
basename = os.path.splitext(target[0].name)[0]
|
||||||
|
# strip off typelib_prefix (such as 'Interop.') so it isn't in the namespace
|
||||||
|
if basename.startswith(typelib_prefix):
|
||||||
|
basename = basename[len(typelib_prefix):]
|
||||||
|
listCmd.append('-namespace:%s' % basename)
|
||||||
|
|
||||||
|
listCmd.append('-out:%s' % target[0].tpath)
|
||||||
|
|
||||||
|
for s in source:
|
||||||
|
if (str(s).endswith('.snk')):
|
||||||
|
listCmd.append('-keyfile:%s' % s.get_string(for_signature))
|
||||||
|
|
||||||
|
return listCmd
|
||||||
|
|
||||||
|
typelibimp_action = SCons.Action.Action('$TYPELIBIMPCOM', '$TYPELIBIMPCOMSTR')
|
||||||
|
|
||||||
|
MsCliTypeLibBuilder = SCons.Builder.Builder(action = '$TYPELIBIMPCOM',
|
||||||
|
source_factory = SCons.Node.FS.default_fs.Entry,
|
||||||
|
emitter = [typelib_emitter, add_depends],
|
||||||
|
suffix = '.dll')
|
||||||
|
|
||||||
|
res_action = SCons.Action.Action('$CLIRCCOM', '$CLIRCCOMSTR')
|
||||||
|
|
||||||
|
def res_emitter(target, source, env):
|
||||||
|
# prepend NAMESPACE if provided
|
||||||
|
if (env.has_key('NAMESPACE')):
|
||||||
|
newtargets = []
|
||||||
|
for t in target:
|
||||||
|
tname = t.name
|
||||||
|
|
||||||
|
# this is a cheesy way to get rid of '.aspx' in .resx file names
|
||||||
|
idx = tname.find('.aspx.')
|
||||||
|
if idx >= 0:
|
||||||
|
tname = tname[:idx] + tname[idx+5:]
|
||||||
|
|
||||||
|
newtargets.append('%s.%s' % (env['NAMESPACE'], tname))
|
||||||
|
return (newtargets, source)
|
||||||
|
else:
|
||||||
|
return (targets, source)
|
||||||
|
|
||||||
|
MsCliResBuilder = SCons.Builder.Builder(action=res_action,
|
||||||
|
emitter=res_emitter,
|
||||||
|
src_suffix='.resx',
|
||||||
|
suffix='.resources',
|
||||||
|
src_builder=[],
|
||||||
|
source_scanner=SCons.Tool.SourceFileScanner)
|
||||||
|
|
||||||
|
SCons.Tool.SourceFileScanner.add_scanner('.resx', SCons.Defaults.CScan)
|
||||||
|
|
||||||
|
def generate(env):
|
||||||
|
envpaths = env['ENV']['PATH']
|
||||||
|
env['CLIREFPATHS'] = envpaths.split(os.pathsep)
|
||||||
|
env['CLIMODPATHS'] = []
|
||||||
|
env['ASSEMBLYREFS'] = []
|
||||||
|
env['NETMODULES'] = []
|
||||||
|
|
||||||
|
env['BUILDERS']['CLIProgram'] = MsCliBuilder
|
||||||
|
env['BUILDERS']['CLIAssembly'] = MsCliLibBuilder
|
||||||
|
env['BUILDERS']['CLILibrary'] = MsCliLibBuilder
|
||||||
|
env['BUILDERS']['CLIModule'] = MsCliModBuilder
|
||||||
|
env['BUILDERS']['CLILink'] = MsCliLinkBuilder
|
||||||
|
env['BUILDERS']['CLIAsmLink'] = MsCliAsmLinkBuilder
|
||||||
|
env['BUILDERS']['CLIRes'] = MsCliResBuilder
|
||||||
|
env['BUILDERS']['CLITypeLib'] = MsCliTypeLibBuilder
|
||||||
|
|
||||||
|
env['CSC'] = env.Detect('gmcs') or 'csc'
|
||||||
|
env['_CSCLIBS'] = "${_stripixes('-r:', CILLIBS, '', '-r', '', __env__)}"
|
||||||
|
env['_CSCLIBPATH'] = "${_stripixes('-lib:', CILLIBPATH, '', '-r', '', __env__)}"
|
||||||
|
env['CSCFLAGS'] = SCons.Util.CLVar('-nologo -noconfig')
|
||||||
|
env['_CSCFLAGS'] = cscFlags
|
||||||
|
env['_CSC_SOURCES'] = cscSources
|
||||||
|
env['_CSC_SOURCES_NO_RESOURCES'] = cscSourcesNoResources
|
||||||
|
env['_CSC_REFS'] = cscRefs
|
||||||
|
env['_CSC_MODS'] = cscMods
|
||||||
|
env['CSCCOM'] = '$CSC $CSCFLAGS $_CSCFLAGS -out:${TARGET.abspath} $_CSC_REFS $_CSC_MODS $_CSC_SOURCES'
|
||||||
|
env['CSCLIBCOM'] = '$CSC -t:library $CSCFLAGS $_CSCFLAGS $_CSCLIBPATH $_CSCLIBS -out:${TARGET.abspath} $_CSC_REFS $_CSC_MODS $_CSC_SOURCES'
|
||||||
|
env['CSCMODCOM'] = '$CSC -t:module $CSCFLAGS $_CSCFLAGS -out:${TARGET.abspath} $_CSC_REFS $_CSC_MODS $_CSC_SOURCES_NO_RESOURCES'
|
||||||
|
env['CLIMODPREFIX'] = ''
|
||||||
|
env['CLIMODSUFFIX'] = '.netmodule'
|
||||||
|
env['CSSUFFIX'] = '.cs'
|
||||||
|
|
||||||
|
# this lets us link .netmodules together into a single assembly
|
||||||
|
env['CLILINK'] = 'link'
|
||||||
|
env['CLILINKFLAGS'] = SCons.Util.CLVar('-nologo -ltcg -dll -noentry')
|
||||||
|
env['_CLILINK_SOURCES'] = cliLinkSources
|
||||||
|
env['CLILINKCOM'] = '$CLILINK $CLILINKFLAGS -out:${TARGET.abspath} $_CLILINK_SOURCES' # $SOURCES'
|
||||||
|
|
||||||
|
env['CLIASMLINK'] = 'al'
|
||||||
|
env['CLIASMLINKFLAGS'] = SCons.Util.CLVar('')
|
||||||
|
env['_ASMLINK_SOURCES'] = alLinkSources
|
||||||
|
env['CLIASMLINKCOM'] = '$CLIASMLINK $CLIASMLINKFLAGS -out:${TARGET.abspath} $_ASMLINK_SOURCES'
|
||||||
|
|
||||||
|
env['CLIRC'] = 'resgen'
|
||||||
|
env['CLIRCFLAGS'] = ''
|
||||||
|
env['CLIRCCOM'] = '$CLIRC $CLIRCFLAGS $SOURCES $TARGETS'
|
||||||
|
|
||||||
|
env['TYPELIBIMP'] = 'tlbimp'
|
||||||
|
env['TYPELIBIMPFLAGS'] = SCons.Util.CLVar('-sysarray')
|
||||||
|
env['_TYPELIBIMPFLAGS'] = tlbimpFlags
|
||||||
|
env['TYPELIBIMPCOM'] = '$TYPELIBIMP $SOURCES $TYPELIBIMPFLAGS $_TYPELIBIMPFLAGS'
|
||||||
|
|
||||||
|
SConsEnvironment.CLIRefs = CLIRefs
|
||||||
|
SConsEnvironment.CLIMods = CLIMods
|
||||||
|
SConsEnvironment.AddToRefPaths = AddToRefPaths
|
||||||
|
SConsEnvironment.AddToModPaths = AddToModPaths
|
||||||
|
SConsEnvironment.PublisherPolicy = PublisherPolicy
|
||||||
|
|
||||||
|
def exists(env):
|
||||||
|
return env.Detect('csc') or env.Detect('gmcs')
|
||||||
156
tools/csharp/csharp.xml
Normal file
156
tools/csharp/csharp.xml
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
<!--
|
||||||
|
__COPYRIGHT__
|
||||||
|
|
||||||
|
This file is processed by the bin/SConsDoc.py module.
|
||||||
|
See its __doc__ string for a discussion of the format.
|
||||||
|
-->
|
||||||
|
<tool name="mscs">
|
||||||
|
<summary>
|
||||||
|
Sets construction variables for the Microsoft CSharp Compiler
|
||||||
|
</summary>
|
||||||
|
</tool>
|
||||||
|
|
||||||
|
<builder name="CLILibrary">
|
||||||
|
<summary>
|
||||||
|
Builds a .NET assembly (dynamically linkable binary) from a list of sources.
|
||||||
|
<example>
|
||||||
|
env.CLILibrary('MyAsm', 'MyAsm.cs')
|
||||||
|
</example>
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="CLILink">
|
||||||
|
<summary>
|
||||||
|
Uses Microsoft C++ linker to link netmodules into a single .NET assembly:
|
||||||
|
|
||||||
|
<example>
|
||||||
|
env.CLILink('Common', ['mod1.netmodule', 'mod2.netmodule'])
|
||||||
|
</example>
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="CLIModule">
|
||||||
|
<summary>
|
||||||
|
Builds a .NET netmodule (statically linkable binary) from a list of sources:
|
||||||
|
|
||||||
|
<example>
|
||||||
|
env.CLIModule('MyMod', 'MyMod.cs')
|
||||||
|
</example>
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="CLIProgram">
|
||||||
|
<summary>
|
||||||
|
Builds a .NET executable from a list of sources.
|
||||||
|
If the $WINEXE value is set, the sources will be compiled as a windows app, rather than a console app:
|
||||||
|
|
||||||
|
<example>
|
||||||
|
env.Program('MyApp', 'MyApp.cs', WINEXE=1)
|
||||||
|
</example>
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="CLIRes">
|
||||||
|
<summary>
|
||||||
|
Builds a Microsoft binary resource file (extension of .resources) from XML source files.
|
||||||
|
If the $NAMESPACE value is set, its value is prepended to the name of the target file:
|
||||||
|
|
||||||
|
<example>
|
||||||
|
env.CLIRes('app.resx', NAMESPACE='MyCompany.ProductX')
|
||||||
|
</example>
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<builder name="CLITypeLib">
|
||||||
|
<summary>
|
||||||
|
Builds a .NET interop assembly that contains converted type definitions found within a COM type library DLL. Prepends the .NET assembly with 'Interop.':
|
||||||
|
|
||||||
|
<example>
|
||||||
|
env.CLITypeLib('MyLib', ['MyLib.dll', 'keyfile.snk'])
|
||||||
|
</example>
|
||||||
|
</summary>
|
||||||
|
</builder>
|
||||||
|
|
||||||
|
<cvar name="CLILINK">
|
||||||
|
<summary>
|
||||||
|
The Microsoft C++ linker.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="CLILINKFLAGS">
|
||||||
|
<summary>
|
||||||
|
General options passed to the Microsoft C++ linker.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="CLILINKCOM">
|
||||||
|
<summary>
|
||||||
|
The command line used to link .NET netmodules into an assembly. Any options specified in the $CLILINKFLAGS construction variable is included on this command line.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="CSC">
|
||||||
|
<summary>
|
||||||
|
The CSharp Compiler.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="CSCFLAGS">
|
||||||
|
<summary>
|
||||||
|
General options that are passed to the CSharp Compiler.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="CSCCOM">
|
||||||
|
<summary>
|
||||||
|
The command line used to compile a CSharp source file to a console or windows executable. Any options specified in the $CSCFLAGS is included on this command line.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="CSCLIBCOM">
|
||||||
|
<summary>
|
||||||
|
The command line used to compile a CSharp source file to a .NET assembly. Any options specified in the $CSCFLAGS is included on this command line.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="CSCMODCOM">
|
||||||
|
<summary>
|
||||||
|
The command line used to compile a CSharp source file to a .NET netmodule. Any options specified in the $CSCFLAGS is included on this command line.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="CLIRC">
|
||||||
|
<summary>
|
||||||
|
The Microsoft .NET resource compiler.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="CLIRCFLAGS">
|
||||||
|
<summary>
|
||||||
|
General options passed to the Microsoft .NET resource compiler.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="CLIRCCOM">
|
||||||
|
<summary>
|
||||||
|
The command line used to compile XML resource files to a .NET resource binary. Any options specified in the $CLIRCFLAGS construction variable is included on this command line.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="TYPELIBIMP">
|
||||||
|
<summary>
|
||||||
|
The Microsoft Type Library Importer.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="TYPELIBIMPFLAGS">
|
||||||
|
<summary>
|
||||||
|
General options passed to the Microsoft Type Library Importer.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
|
|
||||||
|
<cvar name="TYPELIBIMPCOM">
|
||||||
|
<summary>
|
||||||
|
The command line used to convert type definitions found within a COM type library into equivalent definitions in a .NET assembly. Any options specified in the $TYPELIBIMPFLAGS construction variable is included on this command line.
|
||||||
|
</summary>
|
||||||
|
</cvar>
|
||||||
56
tools/csharp/mono.py
Normal file
56
tools/csharp/mono.py
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
# -*- mode:python; coding:utf-8; -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2009 The SCons Foundation
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
# a copy of this software and associated documentation files (the
|
||||||
|
# "Software"), to deal in the Software without restriction, including
|
||||||
|
# without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
# permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
# the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included
|
||||||
|
# in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
# A tool for processing C# code.
|
||||||
|
|
||||||
|
# This C# Tool for Mono taken from http://www.scons.org/wiki/CsharpBuilder.
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
import SCons.Builder
|
||||||
|
import SCons.Node.FS
|
||||||
|
import SCons.Util
|
||||||
|
|
||||||
|
csccom = "$CSC $CSCFLAGS -out:${TARGET.abspath} $SOURCES"
|
||||||
|
csclibcom = "$CSC -t:library $CSCLIBFLAGS $_CSCLIBPATH $_CSCLIBS -out:${TARGET.abspath} $SOURCES"
|
||||||
|
|
||||||
|
McsBuilder = SCons.Builder.Builder(action = '$CSCCOM',
|
||||||
|
source_factory = SCons.Node.FS.default_fs.Entry,
|
||||||
|
suffix = '.exe')
|
||||||
|
|
||||||
|
McsLibBuilder = SCons.Builder.Builder(action = '$CSCLIBCOM',
|
||||||
|
source_factory = SCons.Node.FS.default_fs.Entry,
|
||||||
|
suffix = '.dll')
|
||||||
|
|
||||||
|
def generate(env):
|
||||||
|
env['BUILDERS']['CLIProgram'] = McsBuilder
|
||||||
|
env['BUILDERS']['CLILibrary'] = McsLibBuilder
|
||||||
|
|
||||||
|
env['CSC'] = 'mcs'
|
||||||
|
env['_CSCLIBS'] = "${_stripixes('-r:', CILLIBS, '', '-r', '', __env__)}"
|
||||||
|
env['_CSCLIBPATH'] = "${_stripixes('-lib:', CILLIBPATH, '', '-r', '', __env__)}"
|
||||||
|
env['CSCFLAGS'] = SCons.Util.CLVar('')
|
||||||
|
env['CSCCOM'] = SCons.Action.Action(csccom)
|
||||||
|
env['CSCLIBCOM'] = SCons.Action.Action(csclibcom)
|
||||||
|
|
||||||
|
def exists(env):
|
||||||
|
return internal_zip or env.Detect('mcs')
|
||||||
Loading…
Add table
Add a link
Reference in a new issue