Actually just three programming languages in a trenchcoat
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

implement glue patterns

+149 -2
+11
testsuite/glue-patterns/main.tri
··· 1 + proc main!() { 2 + let "hello" <> world = "hello world"; 3 + assert world == " world" 4 + 5 + let hello <> "world" = "hello world"; 6 + assert hello == "hello " 7 + 8 + let "hello" <> "world" = "helloworld"; 9 + 10 + for "goodbye" <> world = "hello world" { exit 1 } 11 + }
+12
trilogy-llvm/core/core.c
··· 413 413 trilogy_value_clone_into(&contents, &s->contents); 414 414 trilogy_tuple_init_new(rv, &atom, &contents); 415 415 } 416 + 417 + bool unglue_start(trilogy_value* rv, trilogy_value* lhs, trilogy_value* rhs) { 418 + trilogy_string_value* lhs_str = trilogy_string_assume(lhs); 419 + trilogy_string_value* rhs_str = trilogy_string_assume(rhs); 420 + return trilogy_string_unglue_start(rv, lhs_str, rhs_str); 421 + } 422 + 423 + bool unglue_end(trilogy_value* rv, trilogy_value* lhs, trilogy_value* rhs) { 424 + trilogy_string_value* lhs_str = trilogy_string_assume(lhs); 425 + trilogy_string_value* rhs_str = trilogy_string_assume(rhs); 426 + return trilogy_string_unglue_end(rv, lhs_str, rhs_str); 427 + }
+2
trilogy-llvm/core/core.h
··· 49 49 void append(trilogy_value* rv, trilogy_value* arr, trilogy_value* val); 50 50 51 51 void glue(trilogy_value* rv, trilogy_value* lhs, trilogy_value* rhs); 52 + void unglue_start(trilogy_value* rv, trilogy_value* lhs, trilogy_value* rhs); 53 + void unglue_end(trilogy_value* rv, trilogy_value* lhs, trilogy_value* rhs); 52 54 53 55 void cons(trilogy_value* rv, trilogy_value* lhs, trilogy_value* rhs); 54 56
+20
trilogy-llvm/core/trilogy_string.c
··· 89 89 return trilogy_string_init_new(rt, len, ptr); 90 90 } 91 91 92 + bool trilogy_string_unglue_start( 93 + trilogy_value* rt, trilogy_string_value* lhs, trilogy_string_value* rhs 94 + ) { 95 + if (rhs->len < lhs->len) return false; 96 + if (strncmp(lhs->contents, rhs->contents, lhs->len) != 0) return false; 97 + trilogy_string_init_new(rt, rhs->len - lhs->len, rhs->contents + lhs->len); 98 + return true; 99 + } 100 + 101 + bool trilogy_string_unglue_end( 102 + trilogy_value* rt, trilogy_string_value* lhs, trilogy_string_value* rhs 103 + ) { 104 + if (lhs->len < rhs->len) return false; 105 + size_t keep_len = lhs->len - rhs->len; 106 + if (strncmp(lhs->contents + keep_len, rhs->contents, rhs->len) != 0) 107 + return false; 108 + trilogy_string_init_new(rt, keep_len, lhs->contents); 109 + return true; 110 + } 111 + 92 112 void trilogy_string_destroy(trilogy_string_value* val) { free(val->contents); }
+7
trilogy-llvm/core/trilogy_string.h
··· 26 26 int trilogy_string_compare( 27 27 trilogy_string_value* lhs, trilogy_string_value* rhs 28 28 ); 29 + 30 + bool trilogy_string_unglue_start( 31 + trilogy_value* rt, trilogy_string_value* lhs, trilogy_string_value* rhs 32 + ); 33 + bool trilogy_string_unglue_end( 34 + trilogy_value* rt, trilogy_string_value* lhs, trilogy_string_value* rhs 35 + );
+52
trilogy-llvm/src/bare.rs
··· 112 112 .into_pointer_value() 113 113 } 114 114 115 + pub(crate) fn unglue_start( 116 + &self, 117 + out: PointerValue<'ctx>, 118 + lhs: PointerValue<'ctx>, 119 + rhs: PointerValue<'ctx>, 120 + name: &str, 121 + ) -> IntValue<'ctx> { 122 + let f = self.declare_bare( 123 + "unglue_start", 124 + self.context.bool_type().fn_type( 125 + &[ 126 + self.context.ptr_type(AddressSpace::default()).into(), 127 + self.context.ptr_type(AddressSpace::default()).into(), 128 + self.context.ptr_type(AddressSpace::default()).into(), 129 + ], 130 + false, 131 + ), 132 + ); 133 + self.builder 134 + .build_call(f, &[out.into(), lhs.into(), rhs.into()], name) 135 + .unwrap() 136 + .try_as_basic_value() 137 + .unwrap_left() 138 + .into_int_value() 139 + } 140 + 141 + pub(crate) fn unglue_end( 142 + &self, 143 + out: PointerValue<'ctx>, 144 + lhs: PointerValue<'ctx>, 145 + rhs: PointerValue<'ctx>, 146 + name: &str, 147 + ) -> IntValue<'ctx> { 148 + let f = self.declare_bare( 149 + "unglue_end", 150 + self.context.bool_type().fn_type( 151 + &[ 152 + self.context.ptr_type(AddressSpace::default()).into(), 153 + self.context.ptr_type(AddressSpace::default()).into(), 154 + self.context.ptr_type(AddressSpace::default()).into(), 155 + ], 156 + false, 157 + ), 158 + ); 159 + self.builder 160 + .build_call(f, &[out.into(), lhs.into(), rhs.into()], name) 161 + .unwrap() 162 + .try_as_basic_value() 163 + .unwrap_left() 164 + .into_int_value() 165 + } 166 + 115 167 #[expect( 116 168 clippy::too_many_arguments, 117 169 reason = "this is a crazy C function sorry"
+45 -2
trilogy-llvm/src/pattern_match.rs
··· 1 1 use crate::codegen::{Codegen, Merger}; 2 - use crate::types::{TAG_ARRAY, TAG_NUMBER, TAG_RECORD, TAG_SET, TAG_STRUCT, TAG_TUPLE}; 2 + use crate::types::{TAG_ARRAY, TAG_NUMBER, TAG_RECORD, TAG_SET, TAG_STRING, TAG_STRUCT, TAG_TUPLE}; 3 3 use inkwell::IntPredicate; 4 4 use inkwell::basic_block::BasicBlock; 5 5 use inkwell::values::{IntValue, PointerValue}; ··· 208 208 on_fail: PointerValue<'ctx>, 209 209 bound_ids: &mut Vec<Id>, 210 210 ) -> Option<()> { 211 + // NOTE: app.argument => lhs 212 + // application.argument => rhs 211 213 match &application.function.value { 212 214 Value::Builtin(builtin) => self.compile_match_apply_builtin( 213 215 *builtin, ··· 285 287 } 286 288 Some(()) 287 289 } 288 - Value::Builtin(Builtin::Glue) => todo!(), 290 + Value::Builtin(Builtin::Glue) => { 291 + let value_ref = self.use_temporary(value).unwrap(); 292 + let tag = self.get_tag(value_ref, ""); 293 + let is_string = self 294 + .builder 295 + .build_int_compare( 296 + IntPredicate::EQ, 297 + tag, 298 + self.tag_type().const_int(TAG_STRING, false), 299 + "", 300 + ) 301 + .unwrap(); 302 + self.pm_cont_if(is_string, on_fail); 303 + 304 + let output = self.allocate_value("unglued"); 305 + self.bind_temporary(output); 306 + if matches!(app.argument.value, Value::String(..)) { 307 + // If left side is a string literal, compare to the start of the string 308 + let lhs = self 309 + .compile_expression(&app.argument, "glue_pattern_lhs") 310 + .unwrap(); 311 + let is_ok = self.unglue_start(output, lhs, value_ref, "did_unglue"); 312 + self.pm_cont_if(is_ok, on_fail); 313 + self.match_pattern(&application.argument, output, on_fail, bound_ids)?; 314 + } else if matches!(application.argument.value, Value::String(..)) { 315 + // If right side is a string literal, compare to the end of the string 316 + let rhs = self 317 + .compile_expression(&application.argument, "glue_pattern_rhs") 318 + .unwrap(); 319 + let is_ok = self.unglue_end(output, value_ref, rhs, "did_unglue"); 320 + self.pm_cont_if(is_ok, on_fail); 321 + self.match_pattern(&app.argument, output, on_fail, bound_ids)?; 322 + } else { 323 + panic!( 324 + "invalid glue pattern: one side should be a string literal, the other should be a pattern" 325 + ); 326 + } 327 + if let Some(temp) = self.use_owned_temporary(output) { 328 + self.trilogy_value_destroy(temp); 329 + } 330 + Some(()) 331 + } 289 332 _ => panic!("only some operators are usable in pattern matching"), 290 333 }, 291 334 _ => panic!("only builtins can be applied in pattern matching context"),