// Issues: #667, #695, #622
-- in.cue --
import (
	"strconv"
	"regexp"
)

// In these test, it is impossible to determine the existence of some arcs due
// to mutual dependence on becoming concrete.
//
// This tests shows the essences of when an existence check cannot be resolved.
minimal: {
	a: {
		if b.port == _|_ {
			port: ""
		}
	}

	b: {
		if a.port == _|_ {
			port: ""
		}
	}
}

small: {
	#userHostPort: #"^(:(?P<port>\d+))?$"#

	p1: {
		#Y: regexp.FindNamedSubmatch(#userHostPort, #X.port)

		#X: {
			if #Y.port == _|_ {
				port: ""
			}
			if #Y.port != _|_ {
				port: ":" + strconv.FormatInt(#Y.port, 10)
			}
		}
	}
}

medium: {
	#userHostPort: #"^(:(?P<port>\d+))?$"#

	p1: {

		#Y: regexp.FindNamedSubmatch(#userHostPort, #X.port)

		// Yield-on-running heuristic: the comp's referenced node Y
		// is not currently being processed, so the comp does not
		// yield and instead reports a cycle error.

		Y: {
			if #Y.port != _|_ {
				port: strconv.Atoi(#Y.port)
			}
		}

		#X: {
			// Can never determine whether Y.port exists as its resolution
			// depends on #Y becoming finalized, which, in turn, depends on #X
			// becoming finalized.
			if Y.port == _|_ {
				port: ""
			}
			if Y.port != _|_ {
				port: ":" + strconv.FormatInt(Y.port, 10)
			}
		}
	}
}

large: {
	#userHostPort: #"^((?P<userinfo>[[:alnum:]]*)@)?(?P<host>[[:alnum:].]+)(:(?P<port>\d+))?$"#

	p1: {

		Y: {
			userinfo: "user"
			host:     "mod.test"
		}

		X: #X.userinfo + #X.host + #X.port

		#X: {
			if Y.userinfo == _|_ {
				userinfo: ""
			}
			if Y.userinfo != _|_ {
				userinfo: Y.userinfo + "@"
			}

			host: Y.host

			if Y.port == _|_ {
				port: ""
			}
			if Y.port != _|_ {
				port: ":" + strconv.FormatInt(Y.port, 10)
			}
		}

		Y: {
			if #Y.userinfo != _|_ {
				userinfo: #Y.userinfo
			}

			host: #Y.host

			if #Y.port != _|_ {
				port: strconv.Atoi(#Y.port)
			}
		}

		#Y: regexp.FindNamedSubmatch(#userHostPort, X)
	}
}
-- out/compile --
--- in.cue
{
  minimal: {
    a: {
      if (〈1;b〉.port == _|_(explicit error (_|_ literal) in source)) {
        port: ""
      }
    }
    b: {
      if (〈1;a〉.port == _|_(explicit error (_|_ literal) in source)) {
        port: ""
      }
    }
  }
  small: {
    #userHostPort: "^(:(?P<port>\\d+))?$"
    p1: {
      #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;#X〉.port)
      #X: {
        if (〈1;#Y〉.port == _|_(explicit error (_|_ literal) in source)) {
          port: ""
        }
        if (〈1;#Y〉.port != _|_(explicit error (_|_ literal) in source)) {
          port: (":" + 〈import;strconv〉.FormatInt(〈2;#Y〉.port, 10))
        }
      }
    }
  }
  medium: {
    #userHostPort: "^(:(?P<port>\\d+))?$"
    p1: {
      #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;#X〉.port)
      Y: {
        if (〈1;#Y〉.port != _|_(explicit error (_|_ literal) in source)) {
          port: 〈import;strconv〉.Atoi(〈2;#Y〉.port)
        }
      }
      #X: {
        if (〈1;Y〉.port == _|_(explicit error (_|_ literal) in source)) {
          port: ""
        }
        if (〈1;Y〉.port != _|_(explicit error (_|_ literal) in source)) {
          port: (":" + 〈import;strconv〉.FormatInt(〈2;Y〉.port, 10))
        }
      }
    }
  }
  large: {
    #userHostPort: "^((?P<userinfo>[[:alnum:]]*)@)?(?P<host>[[:alnum:].]+)(:(?P<port>\\d+))?$"
    p1: {
      Y: {
        userinfo: "user"
        host: "mod.test"
      }
      X: ((〈0;#X〉.userinfo + 〈0;#X〉.host) + 〈0;#X〉.port)
      #X: {
        if (〈1;Y〉.userinfo == _|_(explicit error (_|_ literal) in source)) {
          userinfo: ""
        }
        if (〈1;Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) {
          userinfo: (〈2;Y〉.userinfo + "@")
        }
        host: 〈1;Y〉.host
        if (〈1;Y〉.port == _|_(explicit error (_|_ literal) in source)) {
          port: ""
        }
        if (〈1;Y〉.port != _|_(explicit error (_|_ literal) in source)) {
          port: (":" + 〈import;strconv〉.FormatInt(〈2;Y〉.port, 10))
        }
      }
      Y: {
        if (〈1;#Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) {
          userinfo: 〈2;#Y〉.userinfo
        }
        host: 〈1;#Y〉.host
        if (〈1;#Y〉.port != _|_(explicit error (_|_ literal) in source)) {
          port: 〈import;strconv〉.Atoi(〈2;#Y〉.port)
        }
      }
      #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;X〉)
    }
  }
}
