-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbmatch.red
83 lines (76 loc) · 2.66 KB
/
bmatch.red
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
Red [
title: "BMATCH mezzanine"
purpose: "Detect possibly mismatched brackets positions from indentation"
author: @hiiamboris
license: BSD-3
provides: bmatch
depends: [detab composite]
notes: {
Ever had an error about unclosed bracket in a 1000+ line file?
This script turns the challenge of finding it into a triviality.
This is a mezz version, for use with the Smarter Load experiment.
}
]
; #include %tabs.red
; #include %composite.red
; #include https://gitlab.com/hiiamboris/red-mezz-warehouse/-/raw/master/tabs.red
; #include https://gitlab.com/hiiamboris/red-mezz-warehouse/-/raw/master/composite.red
bmatch: function [
"Detect unmatched brackets based on indentation"
source [string! binary!]
/origin script [file! url! string!] "Filename where the data comes from"
/tabsize tab [integer!] "Override tab size (default: 4)"
/tolerance tol [integer!] "Min. indentation mismatch to report (default: 0)"
/into tgt [string!] "Buffer to output messages into (otherwise prints)"
/throw "Throw the lexer error if any (otherwise ignores)"
][
tol: max 0 any [tol 0]
tab: max 0 any [tab 4]
script: any [script "(unknown)"]
report: either into [ func [s][repend tgt [s #"^/"]] ][ :print ]
source: detab/size/into source tab clear #{} ;-- using binary because transcode works with binary internally
remove-each c source [c = #"^M"] ;@@ otherwise each CR counts as a line!!
indents: clear []
parse source [collect into indents any [ ;-- list possible indentations for all lines
s1: any #" " s2: opt [some #"|" any #" "] s3: ;-- special case for parse's ` | [` pattern - accept both indents
keep (as-pair offset? s1 s2 offset? s1 s3)
thru [#"^/" | end]
]]
types: reduce [block! paren! string! map!]
opened: clear []
finish: [
foreach [line type] opened [
report #composite "(script): No ending (type) marker after opening at line (line)"
]
]
transcode/into/trace source clear [] function [event input type line token] [
[open close error]
unless find types type [return true]
switch event [
open [reduce/into [line type] tail opened]
close [
take/last opened
line1: take/last opened
either line1 [
i1: indents/:line1 i2: indents/:line
dist: max i1/1 - i2 i1/2 - i2 ;-- find the closest indentation variant
if tol < max dist/1 dist/2 [
report #composite "(script): Unbalanced (type) markers between lines (line1) and (line)"
]
][
report #composite "(script): Unexpected closing (type) marker at line (line)"
]
]
error [
unless throw [
input: next input ;-- advance input or it deadlocks
return false
]
do finish
]
]
true
]
do finish
tgt
]