diff --git a/pkg/runtime/codegen.go b/pkg/runtime/codegen.go index dbf6c9d..ecf64fd 100644 --- a/pkg/runtime/codegen.go +++ b/pkg/runtime/codegen.go @@ -8,6 +8,7 @@ import ( "io" "path/filepath" "reflect" + "regexp" "sort" "strings" "time" @@ -484,6 +485,10 @@ func (g *Generator) generateValue(value any) string { case time.Duration: alias := g.addImportWithAlias("time") return fmt.Sprintf("%s.Duration(%d)", alias, int64(v)) + case *regexp.Regexp: + alias := g.addImportWithAlias("regexp") + // Use MustCompile since we know the pattern is valid (it compiled successfully in the reader) + return fmt.Sprintf("%s.MustCompile(%#v)", alias, v.String()) case *lang.BigDecimal: return g.generateBigDecimalValue(v) case bool: diff --git a/pkg/runtime/testdata/codegen/test/regex_literal.glj b/pkg/runtime/testdata/codegen/test/regex_literal.glj new file mode 100644 index 0000000..28628e9 --- /dev/null +++ b/pkg/runtime/testdata/codegen/test/regex_literal.glj @@ -0,0 +1,18 @@ +(ns codegen.test.regex-literal) + +;; Test regex literal compilation with various patterns +(def pattern-literal #"[a-z]+") + +;; Test with special characters that need escaping +(def pattern-with-backslash #"\\d+") +(def pattern-with-quotes #"\"quoted\"") +(def pattern-with-newline #"line1\nline2") +(def pattern-complex #"^(?:foo|bar)\s*=\s*(['\"]?)(.+?)$") + +;; Test re-pattern function call +(def pattern-function (re-pattern "[0-9]+")) + +;; Test using the patterns +(defn test-match [s] + (and (re-matches pattern-literal "hello") + (re-matches pattern-function "12345"))) \ No newline at end of file diff --git a/pkg/runtime/testdata/codegen/test/regex_literal/load.go.out b/pkg/runtime/testdata/codegen/test/regex_literal/load.go.out new file mode 100644 index 0000000..8b33afa --- /dev/null +++ b/pkg/runtime/testdata/codegen/test/regex_literal/load.go.out @@ -0,0 +1,162 @@ +// Code generated by glojure codegen. DO NOT EDIT. + +package regex_DASH_literal + +import ( + fmt "fmt" + lang "github.com/glojurelang/glojure/pkg/lang" + runtime "github.com/glojurelang/glojure/pkg/runtime" + reflect "reflect" + regexp4 "regexp" +) + +func init() { + runtime.RegisterNSLoader("codegen/test/regex_literal", LoadNS) +} + +func checkDerefVar(v *lang.Var) any { + if v.IsMacro() { + panic(lang.NewIllegalArgumentError(fmt.Sprintf("can't take value of macro: %v", v))) + } + return v.Get() +} + +func checkArity(args []any, expected int) { + if len(args) != expected { + panic(lang.NewIllegalArgumentError("wrong number of arguments (" + fmt.Sprint(len(args)) + ")")) + } +} + +func checkArityGTE(args []any, min int) { + if len(args) < min { + panic(lang.NewIllegalArgumentError("wrong number of arguments (" + fmt.Sprint(len(args)) + ")")) + } +} + +// LoadNS initializes the namespace "codegen.test.regex-literal" +func LoadNS() { + sym_clojure_DOT_core := lang.NewSymbol("clojure.core") + sym_codegen_DOT_test_DOT_regex_DASH_literal := lang.NewSymbol("codegen.test.regex-literal") + sym_pattern_DASH_complex := lang.NewSymbol("pattern-complex") + sym_pattern_DASH_function := lang.NewSymbol("pattern-function") + sym_pattern_DASH_literal := lang.NewSymbol("pattern-literal") + sym_pattern_DASH_with_DASH_backslash := lang.NewSymbol("pattern-with-backslash") + sym_pattern_DASH_with_DASH_newline := lang.NewSymbol("pattern-with-newline") + sym_pattern_DASH_with_DASH_quotes := lang.NewSymbol("pattern-with-quotes") + sym_re_DASH_matches := lang.NewSymbol("re-matches") + sym_s := lang.NewSymbol("s") + sym_test_DASH_match := lang.NewSymbol("test-match") + kw_arglists := lang.NewKeyword("arglists") + kw_column := lang.NewKeyword("column") + kw_end_DASH_column := lang.NewKeyword("end-column") + kw_end_DASH_line := lang.NewKeyword("end-line") + kw_file := lang.NewKeyword("file") + kw_line := lang.NewKeyword("line") + kw_ns := lang.NewKeyword("ns") + kw_rettag := lang.NewKeyword("rettag") + // var clojure.core/re-matches + var_clojure_DOT_core_re_DASH_matches := lang.InternVarName(sym_clojure_DOT_core, sym_re_DASH_matches) + // var codegen.test.regex-literal/pattern-complex + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_complex := lang.InternVarName(sym_codegen_DOT_test_DOT_regex_DASH_literal, sym_pattern_DASH_complex) + // var codegen.test.regex-literal/pattern-function + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_function := lang.InternVarName(sym_codegen_DOT_test_DOT_regex_DASH_literal, sym_pattern_DASH_function) + // var codegen.test.regex-literal/pattern-literal + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_literal := lang.InternVarName(sym_codegen_DOT_test_DOT_regex_DASH_literal, sym_pattern_DASH_literal) + // var codegen.test.regex-literal/pattern-with-backslash + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_with_DASH_backslash := lang.InternVarName(sym_codegen_DOT_test_DOT_regex_DASH_literal, sym_pattern_DASH_with_DASH_backslash) + // var codegen.test.regex-literal/pattern-with-newline + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_with_DASH_newline := lang.InternVarName(sym_codegen_DOT_test_DOT_regex_DASH_literal, sym_pattern_DASH_with_DASH_newline) + // var codegen.test.regex-literal/pattern-with-quotes + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_with_DASH_quotes := lang.InternVarName(sym_codegen_DOT_test_DOT_regex_DASH_literal, sym_pattern_DASH_with_DASH_quotes) + // var codegen.test.regex-literal/test-match + var_codegen_DOT_test_DOT_regex_DASH_literal_test_DASH_match := lang.InternVarName(sym_codegen_DOT_test_DOT_regex_DASH_literal, sym_test_DASH_match) + // reference fmt to avoid unused import error + _ = fmt.Printf + // reference reflect to avoid unused import error + _ = reflect.TypeOf + ns := lang.FindOrCreateNamespace(sym_codegen_DOT_test_DOT_regex_DASH_literal) + _ = ns + // pattern-complex + { + tmp0 := sym_pattern_DASH_complex.WithMeta(lang.NewMap(kw_file, "codegen/test/regex_literal.glj", kw_line, int(10), kw_column, int(6), kw_end_DASH_line, int(10), kw_end_DASH_column, int(20), kw_ns, lang.FindOrCreateNamespace(sym_codegen_DOT_test_DOT_regex_DASH_literal))).(*lang.Symbol) + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_complex = ns.InternWithValue(tmp0, regexp4.MustCompile("^(?:foo|bar)\\s*=\\s*(['\\\"]?)(.+?)$"), true) + if tmp0.Meta() != nil { + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_complex.SetMeta(tmp0.Meta().(lang.IPersistentMap)) + } + } + // pattern-function + { + tmp0 := sym_pattern_DASH_function.WithMeta(lang.NewMap(kw_file, "codegen/test/regex_literal.glj", kw_line, int(13), kw_column, int(6), kw_end_DASH_line, int(13), kw_end_DASH_column, int(21), kw_ns, lang.FindOrCreateNamespace(sym_codegen_DOT_test_DOT_regex_DASH_literal))).(*lang.Symbol) + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_function = ns.InternWithValue(tmp0, regexp4.MustCompile("[0-9]+"), true) + if tmp0.Meta() != nil { + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_function.SetMeta(tmp0.Meta().(lang.IPersistentMap)) + } + } + // pattern-literal + { + tmp0 := sym_pattern_DASH_literal.WithMeta(lang.NewMap(kw_file, "codegen/test/regex_literal.glj", kw_line, int(4), kw_column, int(6), kw_end_DASH_line, int(4), kw_end_DASH_column, int(20), kw_ns, lang.FindOrCreateNamespace(sym_codegen_DOT_test_DOT_regex_DASH_literal))).(*lang.Symbol) + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_literal = ns.InternWithValue(tmp0, regexp4.MustCompile("[a-z]+"), true) + if tmp0.Meta() != nil { + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_literal.SetMeta(tmp0.Meta().(lang.IPersistentMap)) + } + } + // pattern-with-backslash + { + tmp0 := sym_pattern_DASH_with_DASH_backslash.WithMeta(lang.NewMap(kw_file, "codegen/test/regex_literal.glj", kw_line, int(7), kw_column, int(6), kw_end_DASH_line, int(7), kw_end_DASH_column, int(27), kw_ns, lang.FindOrCreateNamespace(sym_codegen_DOT_test_DOT_regex_DASH_literal))).(*lang.Symbol) + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_with_DASH_backslash = ns.InternWithValue(tmp0, regexp4.MustCompile("\\\\d+"), true) + if tmp0.Meta() != nil { + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_with_DASH_backslash.SetMeta(tmp0.Meta().(lang.IPersistentMap)) + } + } + // pattern-with-newline + { + tmp0 := sym_pattern_DASH_with_DASH_newline.WithMeta(lang.NewMap(kw_file, "codegen/test/regex_literal.glj", kw_line, int(9), kw_column, int(6), kw_end_DASH_line, int(9), kw_end_DASH_column, int(25), kw_ns, lang.FindOrCreateNamespace(sym_codegen_DOT_test_DOT_regex_DASH_literal))).(*lang.Symbol) + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_with_DASH_newline = ns.InternWithValue(tmp0, regexp4.MustCompile("line1\\nline2"), true) + if tmp0.Meta() != nil { + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_with_DASH_newline.SetMeta(tmp0.Meta().(lang.IPersistentMap)) + } + } + // pattern-with-quotes + { + tmp0 := sym_pattern_DASH_with_DASH_quotes.WithMeta(lang.NewMap(kw_file, "codegen/test/regex_literal.glj", kw_line, int(8), kw_column, int(6), kw_end_DASH_line, int(8), kw_end_DASH_column, int(24), kw_ns, lang.FindOrCreateNamespace(sym_codegen_DOT_test_DOT_regex_DASH_literal))).(*lang.Symbol) + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_with_DASH_quotes = ns.InternWithValue(tmp0, regexp4.MustCompile("\\\"quoted\\\""), true) + if tmp0.Meta() != nil { + var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_with_DASH_quotes.SetMeta(tmp0.Meta().(lang.IPersistentMap)) + } + } + // test-match + { + tmp0 := sym_test_DASH_match.WithMeta(lang.NewMap(kw_file, "codegen/test/regex_literal.glj", kw_line, int(16), kw_column, int(7), kw_end_DASH_line, int(16), kw_end_DASH_column, int(16), kw_arglists, lang.NewList(lang.NewVector(sym_s)), kw_ns, lang.FindOrCreateNamespace(sym_codegen_DOT_test_DOT_regex_DASH_literal))).(*lang.Symbol) + var tmp1 lang.FnFunc + tmp1 = lang.NewFnFunc(func(args ...any) any { + checkArity(args, 1) + v2 := args[0] + _ = v2 + var tmp3 any + { // let + // let binding "and__0__auto__" + tmp4 := checkDerefVar(var_clojure_DOT_core_re_DASH_matches) + tmp5 := checkDerefVar(var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_literal) + tmp6 := lang.Apply(tmp4, []any{tmp5, "hello"}) + var v7 any = tmp6 + _ = v7 + var tmp8 any + if lang.IsTruthy(v7) { + tmp9 := checkDerefVar(var_clojure_DOT_core_re_DASH_matches) + tmp10 := checkDerefVar(var_codegen_DOT_test_DOT_regex_DASH_literal_pattern_DASH_function) + tmp11 := lang.Apply(tmp9, []any{tmp10, "12345"}) + tmp8 = tmp11 + } else { + tmp8 = v7 + } + tmp3 = tmp8 + } // end let + return tmp3 + }) + tmp1 = tmp1.WithMeta(lang.NewMap(kw_rettag, nil)).(lang.FnFunc) + var_codegen_DOT_test_DOT_regex_DASH_literal_test_DASH_match = ns.InternWithValue(tmp0, tmp1, true) + if tmp0.Meta() != nil { + var_codegen_DOT_test_DOT_regex_DASH_literal_test_DASH_match.SetMeta(tmp0.Meta().(lang.IPersistentMap)) + } + } +}