hassl 0.2.0__py3-none-any.whl → 0.2.1__py3-none-any.whl

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.
hassl/cli.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import argparse
2
2
  import os, json
3
+ from .parser.loader import load_grammar_text
3
4
  from .parser.transform import HasslTransformer
4
5
  from .ast.nodes import Program
5
6
  from lark import Lark
@@ -7,11 +8,10 @@ from .semantics.analyzer import analyze
7
8
  from .codegen.package import emit_package
8
9
  from .codegen import generate as codegen_generate
9
10
 
10
- GRAMMAR_PATH = os.path.join(os.path.dirname(__file__), "parser", "hassl.lark")
11
+ #GRAMMAR_PATH = os.path.join(os.path.dirname(__file__), "parser", "hassl.lark")
11
12
 
12
13
  def parse_hassl(text: str) -> Program:
13
- with open(GRAMMAR_PATH) as f:
14
- grammar = f.read()
14
+ grammar = load_grammar_text()
15
15
  parser = Lark(grammar, start="start", parser="lalr", maybe_placeholders=False)
16
16
  tree = parser.parse(text)
17
17
  program = HasslTransformer().transform(tree)
@@ -0,0 +1,139 @@
1
+ // HASSL grammar — unified if_clause w/ optional inside/outside qualifier
2
+ // + additive schedule support
3
+
4
+ start: stmt*
5
+
6
+ stmt: alias
7
+ | sync
8
+ | rule
9
+ | schedule_decl // NEW (additive)
10
+
11
+ // --- Aliases ---
12
+ alias: "alias" CNAME "=" entity
13
+
14
+ // --- Sync ---
15
+ sync: "sync" synctype "[" entity_list "]" "as" CNAME syncopts?
16
+
17
+ ONOFF: "onoff"
18
+ DIMMER: "dimmer"
19
+ ATTRIBUTE: "attribute"
20
+ SHARED: "shared"
21
+ ALL: "all"
22
+ synctype: ONOFF | DIMMER | ATTRIBUTE | SHARED | ALL
23
+
24
+ syncopts: "{" ("invert" ":" entity_list) "}"
25
+
26
+ // --- Rules ---
27
+ // Allow qualifier inside (...) and/or after ) — both optional
28
+ // (augmented to allow schedule clauses inside rules)
29
+ rule: "rule" CNAME ":" rule_clause+
30
+
31
+ rule_clause: if_clause
32
+ | rule_schedule_use // NEW
33
+ | rule_schedule_inline // NEW
34
+
35
+ if_clause: "if" "(" expr qualifier? ")" qualifier? "then" actions
36
+
37
+ // ---- Conditions ----
38
+ qualifier: "not_by" ( "this" | "any_hassl" | "rule" "(" CNAME ")" )
39
+
40
+ ?expr: expr "||" andexpr -> or_
41
+ | andexpr
42
+ ?andexpr: andexpr "&&" term -> and_
43
+ | term
44
+ ?term: "!" term -> not_
45
+ | "(" expr ")"
46
+ | comparison
47
+
48
+ comparison: operand OP operand
49
+ | operand -> bare_operand
50
+
51
+ OP: "==" | "!=" | "<" | ">" | "<=" | ">="
52
+
53
+ operand: entity | CNAME | STATE | NUMBER | STRING
54
+
55
+ STATE: "on" | "off"
56
+ NUMBER: INT | SIGNED_NUMBER
57
+
58
+ // ---- Actions ----
59
+ actions: action (";" action)*
60
+
61
+ action: assign
62
+ | attr_assign
63
+ | waitact
64
+ | rulectrl
65
+ | tagact
66
+
67
+ assign: CNAME "=" STATE ("for" dur)?
68
+
69
+ // Attribute assignment: allow alias.attr and full entity paths
70
+ attr_assign: CNAME "." CNAME ("." CNAME)* "." CNAME "=" NUMBER
71
+ | CNAME "." CNAME "=" NUMBER
72
+
73
+ waitact: "wait" "(" condition "for" dur ")" action
74
+ // condition used by wait(): allow expr + optional qualifier inside the parens
75
+ condition: expr qualifier?
76
+
77
+ rulectrl: ("disable" | "enable") "rule" CNAME ("for" dur | "until" timepoint)
78
+ tagact: "tag" CNAME "=" (STRING | CNAME | NUMBER)
79
+
80
+ // Durations
81
+ dur: INT UNIT
82
+ UNIT: "ms" | "s" | "m" | "h" | "d"
83
+
84
+ // Timepoint placeholder (kept simple)
85
+ timepoint: CNAME
86
+
87
+ // ---------- Schedules (additive) ----------
88
+ SCHEDULE: "schedule"
89
+ USE: "use"
90
+ FROM: "from"
91
+ TO: "to"
92
+ UNTIL: "until"
93
+ ENABLE: "enable"
94
+ DISABLE: "disable"
95
+ SUNRISE: "sunrise"
96
+ SUNSET: "sunset"
97
+
98
+ TIME_HHMM: /[0-2]?\d:[0-5]\d/
99
+ OFFSET: /[+-]\d+(ms|s|m|h|d)/
100
+
101
+ // Reusable named schedule declarations
102
+ schedule_decl: SCHEDULE CNAME ":" schedule_clause+
103
+
104
+ // Clauses usable both in declarations and inline
105
+ schedule_clause: schedule_op FROM time_spec schedule_end? ";"
106
+ schedule_op: ENABLE | DISABLE
107
+ schedule_end: TO time_spec -> schedule_to
108
+ | UNTIL time_spec -> schedule_until
109
+
110
+ // Rule-level usage
111
+ rule_schedule_use: SCHEDULE USE name_list ";"
112
+ name_list: CNAME ("," CNAME)*
113
+
114
+ // Inline schedule block inside a rule
115
+ rule_schedule_inline: SCHEDULE schedule_clause+
116
+
117
+ // Time specifications
118
+ time_spec: TIME_HHMM -> time_clock
119
+ | sun_spec
120
+ | entity
121
+ | CNAME
122
+
123
+ sun_spec: (SUNRISE|SUNSET) OFFSET? -> time_sun
124
+
125
+ // ---- Atoms ----
126
+ entity_list: member ("," member)*
127
+ member: entity | CNAME
128
+
129
+ entity: CNAME ("." CNAME)+
130
+
131
+ // ---- Lexer ----
132
+ %import common.CNAME
133
+ %import common.WS
134
+ %import common.ESCAPED_STRING -> STRING
135
+ %import common.INT
136
+ %import common.SIGNED_NUMBER
137
+ LINE_COMMENT: /\/\/[^\n]*/
138
+ %ignore LINE_COMMENT
139
+ %ignore WS
hassl/parser/loader.py ADDED
@@ -0,0 +1,6 @@
1
+ # hassl/parser/loader.py
2
+ from importlib.resources import files
3
+
4
+ def load_grammar_text():
5
+ """Read the embedded hassl.lark grammar safely from the installed package."""
6
+ return (files("hassl.parser") / "hassl.lark").read_text(encoding="utf-8")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hassl
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: HASSL: Home Assistant Simple Scripting Language
5
5
  Home-page: https://github.com/adanowitz/hassl
6
6
  Author: adanowitz
@@ -1,5 +1,5 @@
1
1
  hassl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- hassl/cli.py,sha256=rp9C-W-Jy_Lxb9sw2mXR-3_KRLTBil5Xy5q5EYdLZT8,1503
2
+ hassl/cli.py,sha256=yCtfMQHzKCmORDypwxtbGQywLvdERLo3BLYSC2WUxu8,1522
3
3
  hassl/ast/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  hassl/ast/nodes.py,sha256=HINbu3o_hEMDD5G9TgYeqAev-Af0Vacqc_gwQQnpiy0,762
5
5
  hassl/codegen/__init__.py,sha256=NgEw86oHlsk7cQrHz8Ttrtp68Cm7WKceTWRr02SDfjo,854
@@ -7,13 +7,15 @@ hassl/codegen/package.py,sha256=9dcIjszhGXV26Hwr_rKHLz6yYbElyIegfhlXGi5Q0sY,1661
7
7
  hassl/codegen/rules_min.py,sha256=2ko9bFRZujXw7lt5k8L6UbfmTwS2PCWfub5M6Lwkg4I,28330
8
8
  hassl/codegen/yaml_emit.py,sha256=VTNnR_uvSSqsL7kX5NyXuPUZh5FK36a_sUFsRyrQOS8,2207
9
9
  hassl/parser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ hassl/parser/hassl.lark,sha256=YIeY8ncd6nwBzS54A5JbvLhRiQd0u6ftea4nZac4_cA,3361
11
+ hassl/parser/loader.py,sha256=xwhdoMkmXskanY8IhqIOfkcOkkn33goDnsbjzS66FL8,249
10
12
  hassl/parser/transform.py,sha256=dNTyPW9sOw09vBfvWMFSRRiTnOzZQWJvISV1o1aouD4,9481
11
13
  hassl/semantics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
14
  hassl/semantics/analyzer.py,sha256=1x2bAJXj8hsT_IBoxgfTFV0MmVMXcfjqzl_gWo-WuI8,5195
13
15
  hassl/semantics/domains.py,sha256=-OuhA4RkOLVaLnBxhKfJFjiQMYBSTryX9KjHit_8ezI,308
14
- hassl-0.2.0.dist-info/licenses/LICENSE,sha256=hPNSrn93Btl9sU4BkQlrIK1FpuFPvaemdW6-Scz-Xeo,1072
15
- hassl-0.2.0.dist-info/METADATA,sha256=OBOKVzmNcsFlcVZyEp0YF6Z912-FStNKntSUd-0F96A,4929
16
- hassl-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
- hassl-0.2.0.dist-info/entry_points.txt,sha256=qA8jYPZlESNL6V4fJCTPOBXFeEBtjLGGsftXsSo82so,42
18
- hassl-0.2.0.dist-info/top_level.txt,sha256=BPuiULeikxMI3jDVLmv3_n7yjSD9Qrq58bp9af_HixI,6
19
- hassl-0.2.0.dist-info/RECORD,,
16
+ hassl-0.2.1.dist-info/licenses/LICENSE,sha256=hPNSrn93Btl9sU4BkQlrIK1FpuFPvaemdW6-Scz-Xeo,1072
17
+ hassl-0.2.1.dist-info/METADATA,sha256=Z43GbkiT3Sy-Lx3O5eQv8iUdcadYiIx73xac624-sMU,4929
18
+ hassl-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
+ hassl-0.2.1.dist-info/entry_points.txt,sha256=qA8jYPZlESNL6V4fJCTPOBXFeEBtjLGGsftXsSo82so,42
20
+ hassl-0.2.1.dist-info/top_level.txt,sha256=BPuiULeikxMI3jDVLmv3_n7yjSD9Qrq58bp9af_HixI,6
21
+ hassl-0.2.1.dist-info/RECORD,,
File without changes