sfrp 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.ctags +3 -0
- data/.editorconfig +9 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +629 -0
- data/.travis.yml +12 -0
- data/Gemfile +2 -0
- data/LICENSE +28 -0
- data/README.md +34 -0
- data/Rakefile +1 -0
- data/base-library/Base.sfrp +81 -0
- data/base-library/IO/AVR/ATMEGA8.c +9 -0
- data/base-library/IO/AVR/ATMEGA8.h +6 -0
- data/base-library/IO/AVR/ATMEGA8.sfrp +4 -0
- data/base-library/IO/STDIO.c +40 -0
- data/base-library/IO/STDIO.h +13 -0
- data/base-library/IO/STDIO.sfrp +10 -0
- data/bin/sfrp +7 -0
- data/lib/sfrp.rb +2 -0
- data/lib/sfrp/command.rb +73 -0
- data/lib/sfrp/compiler.rb +94 -0
- data/lib/sfrp/error.rb +4 -0
- data/lib/sfrp/file.rb +18 -0
- data/lib/sfrp/flat/dsl.rb +33 -0
- data/lib/sfrp/flat/elements.rb +90 -0
- data/lib/sfrp/flat/exception.rb +45 -0
- data/lib/sfrp/flat/expression.rb +125 -0
- data/lib/sfrp/flat/set.rb +61 -0
- data/lib/sfrp/input/exception.rb +16 -0
- data/lib/sfrp/input/parser.rb +417 -0
- data/lib/sfrp/input/set.rb +29 -0
- data/lib/sfrp/input/transformer.rb +219 -0
- data/lib/sfrp/low/dsl.rb +126 -0
- data/lib/sfrp/low/element.rb +126 -0
- data/lib/sfrp/low/set.rb +62 -0
- data/lib/sfrp/mono/dsl.rb +120 -0
- data/lib/sfrp/mono/environment.rb +26 -0
- data/lib/sfrp/mono/exception.rb +21 -0
- data/lib/sfrp/mono/expression.rb +124 -0
- data/lib/sfrp/mono/function.rb +86 -0
- data/lib/sfrp/mono/memory.rb +32 -0
- data/lib/sfrp/mono/node.rb +125 -0
- data/lib/sfrp/mono/pattern.rb +69 -0
- data/lib/sfrp/mono/set.rb +151 -0
- data/lib/sfrp/mono/type.rb +210 -0
- data/lib/sfrp/mono/vconst.rb +134 -0
- data/lib/sfrp/output/set.rb +33 -0
- data/lib/sfrp/poly/dsl.rb +171 -0
- data/lib/sfrp/poly/elements.rb +168 -0
- data/lib/sfrp/poly/exception.rb +42 -0
- data/lib/sfrp/poly/expression.rb +170 -0
- data/lib/sfrp/poly/monofier.rb +73 -0
- data/lib/sfrp/poly/set.rb +90 -0
- data/lib/sfrp/poly/typing.rb +197 -0
- data/lib/sfrp/raw/dsl.rb +41 -0
- data/lib/sfrp/raw/elements.rb +164 -0
- data/lib/sfrp/raw/exception.rb +40 -0
- data/lib/sfrp/raw/expression.rb +168 -0
- data/lib/sfrp/raw/namespace.rb +30 -0
- data/lib/sfrp/raw/set.rb +109 -0
- data/lib/sfrp/version.rb +3 -0
- data/sfrp.gemspec +40 -0
- data/spec/sfrp/Test.sfrp +4 -0
- data/spec/sfrp/compiler_spec.rb +17 -0
- data/spec/sfrp/flat/set_spec.rb +40 -0
- data/spec/sfrp/input/parse_test.sfrp +20 -0
- data/spec/sfrp/input/set_spec.rb +18 -0
- data/spec/sfrp/low/set_spec.rb +20 -0
- data/spec/sfrp/mono/expected.yml +295 -0
- data/spec/sfrp/mono/set_spec.rb +152 -0
- data/spec/sfrp/output/set_spec.rb +29 -0
- data/spec/sfrp/poly/set_spec.rb +290 -0
- data/spec/sfrp/raw/set_spec.rb +38 -0
- data/spec/spec_helper.rb +16 -0
- data/test/IntTest/Main.c +5 -0
- data/test/IntTest/Main.h +6 -0
- data/test/IntTest/Main.sfrp +10 -0
- data/test/IntTest/in.txt +3 -0
- data/test/IntTest/out.txt +4 -0
- data/test/MaybeTest/Main.sfrp +8 -0
- data/test/MaybeTest/SubDir/Lib.sfrp +9 -0
- data/test/MaybeTest/in.txt +6 -0
- data/test/MaybeTest/out.txt +6 -0
- data/test/Rakefile +15 -0
- metadata +290 -0
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Copyright (c) 2016, Kensuke Sawada
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
12
|
+
documentation and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
3. Neither the name of the copyright holder nor the names of its
|
15
|
+
contributors may be used to endorse or promote products derived from
|
16
|
+
this software without specific prior written permission.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
20
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
21
|
+
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
22
|
+
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
23
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
24
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
25
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
26
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
28
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
SFRP
|
2
|
+
=====
|
3
|
+
|
4
|
+
Pure Functional Language for microcontrollers.
|
5
|
+
|
6
|
+
[](https://travis-ci.org/sfrp/sfrp)
|
7
|
+
[](https://coveralls.io/github/sfrp/sfrp?branch=master)
|
8
|
+
|
9
|
+
# Install SFRP
|
10
|
+
```
|
11
|
+
$ git clone https://github.com/sfrp/sfrp.git ~/sfrp
|
12
|
+
$ cd ~/sfrp
|
13
|
+
$ rake install
|
14
|
+
```
|
15
|
+
For updating, `git pull && rake install`.
|
16
|
+
|
17
|
+
# Usage Example
|
18
|
+
Write following simple accumulator program.
|
19
|
+
```
|
20
|
+
-- Main.sfrp
|
21
|
+
import Base
|
22
|
+
import IO.STDIO as IO
|
23
|
+
|
24
|
+
in @x from IO.$getInt()
|
25
|
+
out IO.$putInt(@y)
|
26
|
+
|
27
|
+
@y 0 = @x + @@y
|
28
|
+
```
|
29
|
+
|
30
|
+
Compile and Run the program.
|
31
|
+
```
|
32
|
+
$ sfrp Main --build=cc
|
33
|
+
$ ./Main
|
34
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,81 @@
|
|
1
|
+
ptype Int{int} = /^((0x)?[0-9]+)$/\1/
|
2
|
+
ptype Float{float} = /^([0-9]+\.[0-9]+)$/\1f/
|
3
|
+
ptype Bool{int} = True{1} | False{0}
|
4
|
+
ptype Unit{int} = Unit{0}
|
5
|
+
|
6
|
+
type Maybe[a] = Just(a) | Nothing
|
7
|
+
type Either[a, b] = Left(a) | Right(b)
|
8
|
+
type Tuple2[a, b] = Tuple2(a, b)
|
9
|
+
type Tuple3[a, b, c] = Tuple3(a, b, c)
|
10
|
+
type Tuple4[a, b, c, d] = Tuple4(a, b, c, d)
|
11
|
+
type Tuple5[a, b, c, d, e] = Tuple5(a, b, c, d, e)
|
12
|
+
|
13
|
+
fst(pair : (a, b)) : a = x where (x, _) = pair
|
14
|
+
snd(pair : (a, b)) : b = y where (_, y) = pair
|
15
|
+
|
16
|
+
foreign - as '-(Int) : Int
|
17
|
+
foreign + as '+(Int) : Int
|
18
|
+
foreign ! as '!(Bool) : Bool
|
19
|
+
|
20
|
+
infix || 8
|
21
|
+
foreign || as ||(Bool, Bool) : Bool
|
22
|
+
|
23
|
+
infix && 9
|
24
|
+
foreign && as &&(Bool, Bool) : Bool
|
25
|
+
|
26
|
+
infixl | 10
|
27
|
+
foreign | as |(Int, Int) : Int
|
28
|
+
|
29
|
+
infixl ^ 11
|
30
|
+
foreign ^ as ^(Int, Int) : Int
|
31
|
+
|
32
|
+
infixl & 12
|
33
|
+
foreign & as &(Int, Int) : Int
|
34
|
+
|
35
|
+
infixl == 13
|
36
|
+
infixl != 13
|
37
|
+
infixl \= 13
|
38
|
+
foreign == as ==(Int, Int) : Bool
|
39
|
+
foreign != as !=(Int, Int) : Bool
|
40
|
+
foreign \= as \=(Int, Int) : Bool
|
41
|
+
|
42
|
+
infixl < 14
|
43
|
+
infixl <= 14
|
44
|
+
infixl > 14
|
45
|
+
infixl >= 14
|
46
|
+
infixl <. 14
|
47
|
+
infixl <=. 14
|
48
|
+
infixl >. 14
|
49
|
+
infixl >=. 14
|
50
|
+
foreign < as <(Int, Int) : Bool
|
51
|
+
foreign <= as <=(Int, Int) : Bool
|
52
|
+
foreign > as >(Int, Int) : Bool
|
53
|
+
foreign >= as >=(Int, Int) : Bool
|
54
|
+
foreign < as <.(Float, Float) : Bool
|
55
|
+
foreign <= as <=.(Float, Float) : Bool
|
56
|
+
foreign > as >.(Float, Float) : Bool
|
57
|
+
foreign >= as >=.(Float, Float) : Bool
|
58
|
+
|
59
|
+
infixl << 15
|
60
|
+
infixl >> 15
|
61
|
+
foreign << as <<(Int, Int) : Int
|
62
|
+
foreign >> as >>(Int, Int) : Int
|
63
|
+
|
64
|
+
infixl + 16
|
65
|
+
infixl - 16
|
66
|
+
infixl +. 16
|
67
|
+
foreign + as +(Int, Int) : Int
|
68
|
+
foreign - as -(Int, Int) : Int
|
69
|
+
foreign + as +.(Float, Float) : Float
|
70
|
+
foreign - as -.(Float, Float) : Float
|
71
|
+
|
72
|
+
infixl * 17
|
73
|
+
infixl / 17
|
74
|
+
infixl % 17
|
75
|
+
infixl *. 17
|
76
|
+
infixl /. 17
|
77
|
+
foreign * as *(Int, Int) : Int
|
78
|
+
foreign / as /(Int, Int) : Int
|
79
|
+
foreign % as %(Int, Int) : Int
|
80
|
+
foreign * as *.(Float, Float) : Float
|
81
|
+
foreign / as /.(Float, Float) : Float
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
|
4
|
+
int get_int() {
|
5
|
+
int x;
|
6
|
+
if (scanf("%d", &x) == EOF) {
|
7
|
+
exit(0);
|
8
|
+
}
|
9
|
+
return x;
|
10
|
+
}
|
11
|
+
|
12
|
+
int put_int(int x) {
|
13
|
+
printf("%d\n", x);
|
14
|
+
return 0;
|
15
|
+
}
|
16
|
+
|
17
|
+
float get_float() {
|
18
|
+
float x;
|
19
|
+
if (scanf("%f", &x) == EOF) {
|
20
|
+
exit(0);
|
21
|
+
}
|
22
|
+
return x;
|
23
|
+
}
|
24
|
+
|
25
|
+
int put_float(float x) {
|
26
|
+
printf("%f\n", x);
|
27
|
+
return 0;
|
28
|
+
}
|
29
|
+
|
30
|
+
int get_int_pair(int* a, int* b) {
|
31
|
+
if (scanf("%d %d", a, b) == EOF) {
|
32
|
+
exit(0);
|
33
|
+
}
|
34
|
+
return 0;
|
35
|
+
}
|
36
|
+
|
37
|
+
int put_int_pair(int a, int b) {
|
38
|
+
printf("(%d, %d)\n", a, b);
|
39
|
+
return 0;
|
40
|
+
}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import Base
|
2
|
+
|
3
|
+
foreign get_int as $getInt() : Int
|
4
|
+
foreign put_int as $putInt(Int) : Unit
|
5
|
+
|
6
|
+
foreign get_float as $getFloat() : Float
|
7
|
+
foreign put_float as $putFloat(Float) : Unit
|
8
|
+
|
9
|
+
foreign get_int_pair as $getIntPair() : (Int, Int)
|
10
|
+
foreign put_int_pair as $putIntPair(Int, Int) : Unit
|
data/bin/sfrp
ADDED
data/lib/sfrp.rb
ADDED
data/lib/sfrp/command.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'sfrp/compiler'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
module SFRP
|
5
|
+
class Command < Struct.new(
|
6
|
+
:main_file, :out_dir, :show_files, :include_paths, :error_class, :cc
|
7
|
+
)
|
8
|
+
def self.from_argv(argv, include_path)
|
9
|
+
com = new('Main', './output', false, ['.'], false, nil)
|
10
|
+
extract_argv(com, argv)
|
11
|
+
com[:include_paths] << include_path
|
12
|
+
com
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.extract_argv(com, argv)
|
16
|
+
opt_parser = OptionParser.new do |parse|
|
17
|
+
desc = 'show paths of the .c file'
|
18
|
+
parse.on('--show-files', desc) do
|
19
|
+
com.show_files = true
|
20
|
+
end
|
21
|
+
desc = 'specify output directory (default is ./output)'
|
22
|
+
parse.on('--out=DIR_NAME', desc) do |dir|
|
23
|
+
com.out_dir = './' + dir.gsub(/\/$/, '')
|
24
|
+
end
|
25
|
+
desc = 'add include path (multi specification is allowed)'
|
26
|
+
parse.on('--include=PATH', desc) do |path|
|
27
|
+
com.include_paths << path
|
28
|
+
end
|
29
|
+
desc = 'only print error (do not generate compiled file)'
|
30
|
+
parse.on('--only-print-error', desc) do
|
31
|
+
com.out_dir = nil
|
32
|
+
end
|
33
|
+
desc = 'print error class instead of error message'
|
34
|
+
parse.on('--error-class', desc) do
|
35
|
+
com.error_class = true
|
36
|
+
end
|
37
|
+
desc = 'make binary by given command'
|
38
|
+
parse.on('--build=CC', desc) do |cc|
|
39
|
+
com.cc = cc
|
40
|
+
end
|
41
|
+
end
|
42
|
+
args_without_option = opt_parser.parse(argv)
|
43
|
+
case args_without_option.size
|
44
|
+
when 0
|
45
|
+
nil
|
46
|
+
when 1
|
47
|
+
com.main_file = args_without_option[0].gsub(/\.sfrp$/, '')
|
48
|
+
else
|
49
|
+
STDERR.puts 'invalid target specification'
|
50
|
+
exit(1)
|
51
|
+
end
|
52
|
+
rescue OptionParser::InvalidOption => error
|
53
|
+
puts error.message
|
54
|
+
exit(1)
|
55
|
+
end
|
56
|
+
|
57
|
+
def run
|
58
|
+
outs = Compiler.new(main_file, include_paths).compile(out_dir)
|
59
|
+
out_paths = outs.map { |o| out_dir + '/' + o + '.c' }
|
60
|
+
STDOUT.puts out_paths.join("\n") if show_files
|
61
|
+
STDERR.print `#{cc} -o #{main_file} #{out_paths.join(' ')}` if cc
|
62
|
+
rescue SFRP::CompileError => cerr
|
63
|
+
text = error_class ? cerr.class.to_s : cerr.message
|
64
|
+
if out_dir == nil
|
65
|
+
STDOUT.puts text
|
66
|
+
exit(0)
|
67
|
+
else
|
68
|
+
STDERR.puts text
|
69
|
+
exit(1)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'sfrp/input/set'
|
2
|
+
require 'sfrp/raw/set'
|
3
|
+
require 'sfrp/flat/set'
|
4
|
+
require 'sfrp/poly/set'
|
5
|
+
require 'sfrp/mono/set'
|
6
|
+
require 'sfrp/low/set'
|
7
|
+
require 'sfrp/output/set'
|
8
|
+
require 'sfrp/error'
|
9
|
+
require 'sfrp/file'
|
10
|
+
|
11
|
+
module SFRP
|
12
|
+
class Compiler
|
13
|
+
def initialize(main_fmodule_uri, include_paths)
|
14
|
+
@main_fmodule_uri = main_fmodule_uri
|
15
|
+
@include_paths = include_paths
|
16
|
+
end
|
17
|
+
|
18
|
+
def make_input_set
|
19
|
+
Input::Set.new do |s|
|
20
|
+
collect_fmodule_uris(@main_fmodule_uri).each do |uri|
|
21
|
+
content = File.read(to_full_path(uri))
|
22
|
+
s.append_source_file(uri, content)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_output_set
|
28
|
+
make_input_set
|
29
|
+
.to_raw
|
30
|
+
.to_flat
|
31
|
+
.to_poly
|
32
|
+
.to_mono
|
33
|
+
.to_low(collect_include_strs(@main_fmodule_uri))
|
34
|
+
.to_output
|
35
|
+
end
|
36
|
+
|
37
|
+
def compile(output_dir_path = nil)
|
38
|
+
virtual_files = collect_virtual_files(@main_fmodule_uri)
|
39
|
+
output_set = make_output_set
|
40
|
+
output_set.generate!(output_dir_path, virtual_files) if output_dir_path
|
41
|
+
output_file_names
|
42
|
+
end
|
43
|
+
|
44
|
+
def output_file_names
|
45
|
+
['main'] + collect_virtual_files(@main_fmodule_uri).flat_map do |vf|
|
46
|
+
vf.file_ext == 'c' ? [vf.fmodule_uri.gsub('.', '/')] : []
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def collect_fmodule_uris(fmodule_uri, visited = {})
|
53
|
+
return [] if visited.key?(fmodule_uri)
|
54
|
+
visited[fmodule_uri] = true
|
55
|
+
content = File.read(to_full_path(fmodule_uri))
|
56
|
+
content.each_line.each_with_object([fmodule_uri]) do |line, ary|
|
57
|
+
line.match(/import ([A-Z][a-zA-Z0-9]+(\.[A-Z][a-zA-Z0-9]+)*)/) do |m|
|
58
|
+
ary.concat(collect_fmodule_uris(m[1], visited))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def collect_virtual_files(fmodule_uri)
|
64
|
+
collect_fmodule_uris(fmodule_uri).each_with_object([]) do |uri, ary|
|
65
|
+
path = to_full_path(uri)
|
66
|
+
cpath = path.gsub(/\.sfrp$/, '.c')
|
67
|
+
hpath = path.gsub(/\.sfrp$/, '.h')
|
68
|
+
if File.exist?(cpath)
|
69
|
+
ary << VirtualFile.new(uri, 'c', File.read(cpath))
|
70
|
+
end
|
71
|
+
if File.exist?(hpath)
|
72
|
+
ary << VirtualFile.new(uri, 'h', File.read(hpath))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def collect_include_strs(fmodule_uri)
|
78
|
+
collect_virtual_files(fmodule_uri).each_with_object([]) do |vf, ary|
|
79
|
+
if vf.file_ext == 'h'
|
80
|
+
ary << "#{vf.fmodule_uri.gsub('.', '/')}.#{vf.file_ext}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_full_path(fmodule_uri)
|
86
|
+
relative_path = fmodule_uri.gsub('.', '/')
|
87
|
+
@include_paths.each do |path|
|
88
|
+
full_path = path + '/' + relative_path + '.sfrp'
|
89
|
+
return full_path if File.exist?(full_path)
|
90
|
+
end
|
91
|
+
raise FileResolveError.new(fmodule_uri, @include_paths)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|